Skip to content

feat: add Playwright test agents system — interactive recorder CLI, AI agents, and codegen transform#10694

Open
christian-byrne wants to merge 27 commits intomainfrom
playwright-test-agents-system
Open

feat: add Playwright test agents system — interactive recorder CLI, AI agents, and codegen transform#10694
christian-byrne wants to merge 27 commits intomainfrom
playwright-test-agents-system

Conversation

@christian-byrne
Copy link
Copy Markdown
Contributor

@christian-byrne christian-byrne commented Mar 29, 2026

Summary

Three integrated systems for AI-assisted browser test creation, targeting QA testers (non-developers) and AI agents.

What's Added

1. comfy-test CLI (tools/test-recorder/, 26 source files)

Interactive 7-step recording flow: environment checks → project setup → backend verification → test configuration → browser recording → codegen transform → PR creation.

pnpm comfy-test record      # Full guided flow
pnpm comfy-test transform    # Transform raw codegen to conventions
pnpm comfy-test check        # Verify environment prerequisites
pnpm comfy-test list         # List available workflow assets

Key features:

  • Platform-specific install instructions for zero-dev-tools users (macOS/Windows/Linux)
  • 10 prerequisite checks: OS, Xcode CLI, git, Node.js, pnpm, Python, Playwright, gh CLI, dev server, backend
  • Codegen-to-convention transform engine with 8 regex rules + structural transforms
  • PR creation: auto via gh CLI or step-by-step manual GitHub web UI instructions
  • Cross-platform clipboard support (pbcopy/xclip/clip.exe)

2. Playwright AI Agents (.claude/agents/)

Three agents patched with ComfyUI-specific context:

  • Planner — explores the app and creates test plans
  • Generator — converts plans into .spec.ts files using comfyPageFixture
  • Healer — debugs and fixes failing tests with safety rules (never add waitForTimeout, never weaken assertions)

Regeneration scripts (scripts/update-playwright-agents.sh) re-run init-agents and re-apply patches after Playwright updates.

3. Codegen Transform Skill (.claude/skills/codegen-transform/)

Teaches AI agents the same transform rules the CLI uses:

  • @playwright/testcomfyPageFixture imports
  • pagecomfyPage fixture
  • page.goto() → removed (fixture handles navigation)
  • page.locator("canvas")comfyPage.canvas
  • waitForTimeout()comfyPage.nextFrame()
  • Auto-wraps in test.describe with tags and afterEach cleanup

4. Documentation Updates

  • AGENTS.md — added comfy-test commands
  • browser_tests/AGENTS.md — "AI-Assisted Test Creation" section covering all 3 systems
  • browser_tests/README.md — "Recording Tests (For Non-Developers)" section

Files Changed

Area Files Description
CLI tool tools/test-recorder/src/** (26 files) Full TypeScript CLI package
Agents .claude/agents/ (3 files) Patched planner/generator/healer
Skill .claude/skills/codegen-transform/SKILL.md Transform rules for agents
Scripts scripts/update-playwright-agents.sh, scripts/patch-playwright-agents.js Agent regeneration
Config .mcp.json, .oxlintrc.json, knip.config.ts MCP server, lint/knip config
Test browser_tests/tests/seed.spec.ts, browser_tests/specs/README.md Agent seed test
Docs AGENTS.md, browser_tests/AGENTS.md, browser_tests/README.md Documentation
Workspace package.json, pnpm-workspace.yaml, pnpm-lock.yaml Package setup

Testing

  • pnpm comfy-test — CLI runs, shows help
  • pnpm comfy-test list — lists 74 workflow assets
  • pnpm comfy-test check — runs all prerequisite checks
  • TypeScript compiles (tsc --noEmit)
  • All quality gates pass (oxfmt, oxlint, eslint, typecheck, typecheck:browser, knip)

┆Issue is synchronized with this Notion page by Unito

…I agents, and codegen transform

Three integrated systems for AI-assisted browser test creation:

1. comfy-test CLI (tools/test-recorder/)
   - Interactive 7-step recording flow for QA testers and non-developers
   - Environment checks with platform-specific install guidance
   - Codegen-to-convention transform engine
   - PR creation via gh CLI or manual GitHub web UI instructions
   - Commands: record, transform, check, list

2. Playwright AI agents (.claude/agents/)
   - Planner, generator, and healer agents patched with ComfyUI context
   - Regeneration scripts for Playwright updates (scripts/update-playwright-agents.sh)
   - MCP server config (.mcp.json) for agent browser interaction
   - Seed test and specs directory for agent-generated tests

3. Codegen transform skill (.claude/skills/codegen-transform/)
   - Transform rules: @playwright/test → comfyPageFixture, page → comfyPage,
     remove goto, canvas locators, waitForTimeout → nextFrame
   - Structural transforms: wrap in describe with tags, add afterEach cleanup
   - Fixture API reference and before/after examples
@christian-byrne christian-byrne requested a review from a team March 29, 2026 00:45
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Mar 29, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 29, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR introduces a comprehensive test recording and transformation infrastructure for ComfyUI. It adds three Claude agents for test planning, generation, and healing; a CLI tool (@comfyorg/test-recorder) with commands for recording, transforming, and checking environments; system prerequisite checks; transformation rules for converting Playwright codegen output to project conventions; and supporting scripts for patching agent configurations with ComfyUI-specific context.

Changes

Cohort / File(s) Summary
Claude Agents & Skills Configuration
.claude/agents/playwright-test-planner.md, .claude/agents/playwright-test-generator.md, .claude/agents/playwright-test-healer.md, .claude/skills/codegen-transform/SKILL.md
New agent definitions for test planning, code generation, and test healing workflows. Skill defines transformation rules for converting raw Playwright output to ComfyUI conventions (import rewrites, fixture changes, locator mapping, structural wrapping).
MCP & Linter Configuration
.mcp.json, .oxlintrc.json
Registered Playwright MCP server and relaxed no-console linting for test-recorder source files.
System Check Modules
tools/test-recorder/src/checks/*.ts
Environment and service prerequisite verification: platform detection, Xcode/Git/Node/pnpm/Python/Playwright/GitHub CLI availability, backend/dev server connectivity with platform-specific install instructions.
Recording & Transformation Engine
tools/test-recorder/src/recorder/*.ts, tools/test-recorder/src/transform/*.ts
Playwright test recording orchestration, temporary template generation, raw-to-convention code transformation via regex rules and structural transforms, project root discovery, and workflow asset listing.
CLI Commands
tools/test-recorder/src/commands/*.ts, tools/test-recorder/src/index.ts
Interactive CLI commands: record (full workflow from checks through PR creation), transform (code conversion), check (environment verification), list (available workflows); main entrypoint with command routing.
PR Creation Utilities
tools/test-recorder/src/pr/*.ts
GitHub CLI integration for automated PR creation, fallback clipboard copy, and manual PR instruction generation with platform-aware clipboard commands.
UI & Logging Utilities
tools/test-recorder/src/ui/*.ts
Styled terminal output (status indicators, info boxes, step headers) using picocolors and Unicode borders.
Package & Workspace Configuration
tools/test-recorder/package.json, tools/test-recorder/tsconfig.json, tools/test-recorder/README.md, pnpm-workspace.yaml, knip.config.ts, package.json
New test-recorder workspace package with ESM/TypeScript config, build/dev/typecheck scripts, dependencies on @clack/prompts and picocolors, workspace glob expansion, and comfy-test npm script.
Documentation
AGENTS.md, browser_tests/README.md, browser_tests/specs/README.md
Agent role documentation with guardrails (fixture usage, assertion handling, timeout avoidance), interactive recording workflow guide (7 steps), and spec directory placeholder.
Patch Scripts
scripts/patch-playwright-agents.js, scripts/update-playwright-agents.sh
Automated patching of agent markdown files with ComfyUI project context; Bash wrapper to regenerate base agents and apply custom patches.
Tests & Ignores
browser_tests/tests/seed.spec.ts, .gitignore
Seed test bootstrapping ComfyUI environment; ignores temporary recording session file.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as Record CLI
    participant Checks as Environment<br/>Checks
    participant Install as Dependency<br/>Install
    participant Recorder as Playwright<br/>Recorder
    participant Browser as Browser<br/>(Inspector)
    participant Backend as ComfyUI<br/>Backend
    participant Transform as Transform<br/>Engine
    participant Output as Output File

    User->>CLI: pnpm comfy-test record
    CLI->>Checks: Run prerequisite checks
    Checks->>Checks: Platform, Node, pnpm, Python,<br/>Playwright, Git, Xcode, GitHub CLI
    Checks-->>CLI: Results
    CLI->>Install: pnpm install (if needed)
    Install-->>CLI: Dependencies ready
    CLI->>User: Prompt for test name & description
    User-->>CLI: Input provided
    CLI->>Recorder: Create recording session
    Recorder->>Browser: Launch Chromium + Inspector
    Browser->>Backend: Connect to ComfyUI
    Browser-->>User: Ready for interaction
    User->>Browser: Record test steps
    Browser->>Backend: Execute actions
    Browser-->>Recorder: Capture codegen
    User->>Recorder: Stop recording
    Recorder-->>CLI: Raw test code
    CLI->>User: Paste recorded code
    User-->>CLI: Code pasted
    CLI->>Transform: transform(rawCode, options)
    Transform->>Transform: Apply regex rules<br/>+ structural transforms
    Transform-->>CLI: Transformed code
    CLI->>Output: Write to .spec.ts
    Output-->>CLI: File written
    CLI->>User: Show PR creation options
    User->>CLI: Create PR (if authenticated)
    CLI-->>User: PR created or manual steps
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A recorder hops through the browser with flair,
Recording thy tests with precision and care,
Then transforms the code to conventions so fine,
While agents do plan, generate, and refine,
The tests now can heal when they stumble and break,
All wrapped in a CLI for ComfyUI's sake! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.92% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the three core additions: an interactive Playwright test agents system, a recorder CLI, AI agents, and a codegen transform skill — all clearly reflected in the changeset.
Description check ✅ Passed The description is comprehensive and well-structured, covering all three systems with specific file counts, command examples, key features, and testing validation. All required sections are present and detailed.
End-To-End Regression Coverage For Fixes ✅ Passed PR uses 'feat:' language indicating a feature rather than bug fix, and changes multiple files under browser_tests/ including documentation and test files.
Adr Compliance For Entity/Litegraph Changes ✅ Passed PR modifies only test infrastructure files and configuration; no changes to src/lib/litegraph/, src/ecs/, or graph entity-related files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch playwright-test-agents-system

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

🧹 Nitpick comments (9)
tools/test-recorder/src/ui/logger.ts (1)

18-20: Unused wait function.

The wait function is defined but never exported or used. Consider removing it or exporting it if intended for future use.

♻️ Option: Remove or export

Either remove the unused function:

-function wait(label: string) {
-  console.log(`  ${pc.blue('⏳')} ${label}`)
-}

Or export it for use elsewhere:

-function wait(label: string) {
+export function wait(label: string) {
   console.log(`  ${pc.blue('⏳')} ${label}`)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/test-recorder/src/ui/logger.ts` around lines 18 - 20, The function wait
is declared but unused; either remove the unused function wait from the module
to clean up dead code, or if it was intended for external use, export it (e.g.,
add an export for wait) and ensure callers/imports are updated; update any
related tests or imports to reflect the removal or exported symbol so the logger
module has no unused declarations.
tools/test-recorder/src/checks/python.ts (1)

10-11: Use a single stable check name for pass/fail paths.

Returning 'Python' on success and 'Python 3' on failure makes result labeling inconsistent. Use one canonical name in both branches.

Also applies to: 17-38

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/test-recorder/src/checks/python.ts` around lines 10 - 11, The check
uses inconsistent names for the same check across success/failure branches
(e.g., pass('Python', version) vs returning name: 'Python 3'); update all places
in this file (including the pass() calls and the returned result objects in both
success and failure paths, e.g., where name is set) to use one canonical check
name (suggest "Python") so the pass('Python', ...) call and every return { name:
..., ok: ..., version } use the identical string.
tools/test-recorder/package.json (1)

7-14: bin entry appears unused for this private workspace package.

comfy-test is a private package not meant for publication. The actual usage path is the root package's comfy-test script, which runs tsx tools/test-recorder/src/index.ts directly—bypassing the bin entry entirely. The ./dist/index.js target is never built or invoked.

Either remove the unused bin entry, or (if this tool may be published later) add a prepare hook to ensure the dist folder exists:

Suggested fix (if bin is needed)
   "scripts": {
     "build": "tsc",
+    "prepare": "pnpm build",
     "dev": "tsc --watch",
     "typecheck": "tsc --noEmit"
   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/test-recorder/package.json` around lines 7 - 14, The package.json
currently defines a "bin" entry for "comfy-test" pointing to "./dist/index.js"
but that dist artifact is never built or used; either remove the unused "bin"
field entirely, or add a "prepare" npm script that runs the build so the CLI
artifact exists when publishing (e.g., wire a "prepare" script to the existing
"build" task), and ensure "scripts.build" ("tsc") and the "comfy-test" bin name
remain consistent if you keep the bin entry.
tools/test-recorder/src/checks/platform.ts (1)

8-15: Avoid classifying unknown platforms as Linux.

Line 13-14 currently maps every non-macOS/non-Windows platform to Linux, which can yield incorrect install guidance. Consider returning an explicit unknown platform and handling it with generic instructions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/test-recorder/src/checks/platform.ts` around lines 8 - 15, The switch
over os.platform() currently maps any non-'darwin'/'win32' value to 'linux';
change the default case to return 'unknown' (or 'other') instead of 'linux' so
unknown platforms aren't misclassified, and update any call sites that consume
this platform value to handle 'unknown' by showing generic install instructions
or prompting the user for platform details; target the switch statement that
inspects os.platform() and modify the default branch and related
platform-handling logic accordingly.
browser_tests/AGENTS.md (1)

33-38: Add the preferred local Playwright run command to the “After Making Changes” checklist.

Consider including pnpm test:browser:local here so contributors run the same default local E2E command used across the repo.

Based on learnings: For agents making changes locally in the Comfy-Org/ComfyUI_frontend repository, pnpm test:browser:local is the preferred default command for running Playwright E2E tests.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@browser_tests/AGENTS.md` around lines 33 - 38, Update the "After Making
Changes" checklist under the "After Making Changes" heading to include the
preferred local Playwright command by adding a new bullet recommending `pnpm
test:browser:local` so contributors run the same default local E2E command used
across the repo; ensure the entry matches the style of the surrounding bullets
and sits alongside the existing `pnpm typecheck:browser`, `pnpm exec eslint`,
and `pnpm exec oxlint` items.
tools/test-recorder/src/pr/manual.ts (1)

20-20: Normalize path to forward slashes before display.

The function is exported and receives relativePath as a string with no guarantee of normalization. While the current call site in record.ts passes a hardcoded forward-slash path, defensive normalization would align with patterns used elsewhere in the codebase (e.g., build/plugins/comfyAPIPlugin.ts, lint-staged.config.ts) and prevent potential GitHub path misplacement if this function is called with platform-specific separators.

`  3. Set path to: ${options.relativePath.replace(/\\/g, '/')}`,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/test-recorder/src/pr/manual.ts` at line 20, The template currently
inserts options.relativePath directly; normalize it to forward slashes before
display by replacing backslashes with slashes (e.g., transform
options.relativePath via a replace of "\\" with "/") where the template contains
`${options.relativePath}` in the exported function in manual.ts so the displayed
path is always forward-slash normalized.
tools/test-recorder/src/pr/gh.ts (2)

17-36: checkGhAvailable is marked async but performs no asynchronous operations.

The function uses only synchronous execSync calls. Either remove the async keyword or consider using async spawn methods for consistency with the async API.

♻️ Proposed fix
-export async function checkGhAvailable(): Promise<{
+export function checkGhAvailable(): {
   available: boolean
   authenticated: boolean
-}> {
+} {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/test-recorder/src/pr/gh.ts` around lines 17 - 36, The function
checkGhAvailable is declared async but only uses synchronous execSync calls;
remove the async keyword to avoid misleading the API or refactor to use
asynchronous child_process methods (e.g., promisified exec or spawn) instead.
Locate checkGhAvailable and replace the declaration to be a plain synchronous
function (remove async) or change the execSync calls to async equivalents
(promisified exec/child_process.spawn wrapped in promises), ensuring returned
object shape ({ available, authenticated }) and error handling remain the same.

17-36: Consider consolidating with checkGh() in checks/gh.ts to avoid duplication.

Both this function and checkGh() in tools/test-recorder/src/checks/gh.ts execute the same gh --version and gh auth status commands. Consider extracting shared logic or reusing checkGh() here to maintain DRY principles.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/test-recorder/src/pr/gh.ts` around lines 17 - 36, The
checkGhAvailable() implementation duplicates logic from checkGh(); replace its
body by reusing the existing checkGh() helper or extract a shared helper that
runs "gh --version" and "gh auth status" so both checkGh() and
checkGhAvailable() call it; update imports to bring in checkGh() (or the new
shared helper), adapt return shape if needed to match {available:boolean,
authenticated:boolean}, and remove the duplicated execSync calls inside
checkGhAvailable().
tools/test-recorder/src/commands/record.ts (1)

35-42: readMultiline doesn't handle readline errors.

If stdin encounters an error, the promise will never resolve (no rejection handler). Consider adding error handling.

♻️ Proposed fix
 function readMultiline(): Promise<string> {
-  return new Promise((resolve) => {
+  return new Promise((resolve, reject) => {
     const lines: string[] = []
     const rl = createInterface({ input: process.stdin })
     rl.on('line', (line) => lines.push(line))
     rl.on('close', () => resolve(lines.join('\n')))
+    rl.on('error', (err) => reject(err))
   })
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/test-recorder/src/commands/record.ts` around lines 35 - 42, The
readMultiline Promise does not handle stream errors so it can hang; update the
readMultiline function (which uses createInterface and rl) to attach an 'error'
listener that rejects the Promise with the error, and ensure the listener cleans
up (e.g., calls rl.close() or removes listeners) to avoid leaks; also consider
listening to process.stdin 'error' or forwarding that to the same rejection so
any stdin error rejects the Promise instead of leaving it unresolved.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.claude/agents/playwright-test-generator.md:
- Around line 46-59: The example has a syntax error and doesn't follow ComfyUI
test conventions: change the test signature from async { page } to async ({
comfyPage }) and replace all uses of page with comfyPage.page; import the Comfy
fixtures (comfyPageFixture as test and comfyExpect as expect) from the ComfyPage
fixture module; wrap the suite in test.describe with appropriate tags (e.g., {
tag: ['@canvas'] }) and add the required test.afterEach hook that calls
comfyPage.canvasOps.resetView so the suite matches the mandated structure and
fixtures (refer to comfyPageFixture, comfyExpect, test.describe, test.afterEach,
comfyPage.canvasOps.resetView, and comfyPage.page.click).

In @.claude/agents/playwright-test-healer.md:
- Around line 41-44: Update the healer guidance so it no longer tells agents to
auto-mark failing tests with test.fixme(); instead, change the behavior in the
policy text that mentions test.fixme() to require explicit escalation criteria
(e.g., a linked known-issue ID and a short rationale) before recommending or
applying test.fixme(), and add a brief note to the same section explaining that
skips can mask regressions and therefore must be approved with those criteria
rather than applied automatically.

In @.mcp.json:
- Around line 1-12: The mcpServers entry "playwright-test" is using the
nonexistent Playwright subcommand "run-test-mcp-server"; update the "command"
and "args" so the MCP server is invoked via the separate package (e.g., use
"npx" as the command and "@playwright/mcp" in the args) instead of "playwright"
and "run-test-mcp-server", leaving the "mcpServers" and "playwright-test" keys
intact.

In `@AGENTS.md`:
- Around line 52-55: Update AGENTS.md to include a short section describing the
new agent roles added under .claude/agents/: add entries for the planner,
generator, and healer that each state the agent's primary responsibility (e.g.,
Planner: decomposes tasks and creates plans; Generator: produces
outputs/artifacts from plans; Healer: validates outputs and applies
corrections), list high-level guardrails for each (scope limits, data/privacy
rules, allowed actions, failure modes), and reference the directory
.claude/agents/ to show where implementations live so the top-level docs match
the codebase.

In `@scripts/patch-playwright-agents.js`:
- Around line 3-4: The script currently calls readFileSync on generated agent
files and can throw an ambiguous ENOENT if names change; before invoking
readFileSync (where agent file paths are constructed using join and read), add
an existence check (e.g., fs.existsSync or fs.promises.stat) for each expected
file, collect any missing file paths into an array, and if any are missing throw
or log a clear, deterministic error that lists the missing files and hints to
re-run init-agents; update the code paths that build the file list (the same
block around the readFileSync calls) to perform this guard and only attempt to
read files that pass the check.

In `@tools/test-recorder/README.md`:
- Around line 9-14: Update the README transform usage to show the required
positional file argument and optional extra args: change the example line to
`pnpm comfy-test transform <file>` and add a short note that additional
positional arguments (e.g., `testName` and tag(s)) may be provided, matching the
CLI behavior implemented in tools/test-recorder/src/index.ts which enforces the
file positional argument for the transform command.

In `@tools/test-recorder/src/checks/pnpm.ts`:
- Around line 13-16: Replace the hardcoded guidance string "corepack prepare
pnpm@latest --activate" in tools/test-recorder/src/checks/pnpm.ts with a pinned
pnpm version used in the repo (e.g. "corepack prepare pnpm@10.17.1 --activate");
locate the exact string literal "corepack prepare pnpm@latest --activate" and
update it to "corepack prepare pnpm@10.17.1 --activate" (or modify the code to
read the pinned version from package.json if you prefer a programmatic
solution).

In `@tools/test-recorder/src/commands/record.ts`:
- Around line 65-69: The call to spawnSync('pnpm', ['install'], ...) in the
record command doesn't check the returned result, so failures are masked:
capture the result (the value returned by spawnSync), inspect result.status
and/or result.error, and if non-zero or an error is present stop the spinner
with a failure message (use s.stop or s.fail), log or include
result.stderr/stdout for diagnostics, and abort (throw or exit) before calling
pass('Project ready', projectRoot); ensure references include spawnSync, s
(spinner), pass, and projectRoot when making the change.
- Around line 229-238: The call to copyToClipboard(fileContents) ignores its
boolean result so clipboard failures are silent; update the else branch in
record.ts to capture the result (e.g., const copied = await
copyToClipboard(fileContents)), and if copied is false, log or surface a clear
message and fall back to printing the fileContents or otherwise call
printManualInstructions with a note that clipboard failed; reference the symbols
copyToClipboard, fileContents, outputPath, slug, and printManualInstructions to
find and modify the code path.

In `@tools/test-recorder/src/commands/transform.ts`:
- Around line 29-46: The current string-based path handling can break on Windows
and may overwrite the input file; import and use Node's path utilities (e.g.,
path.basename, path.dirname, path.join, path.parse) to compute testName and
outputPath robustly: derive testName from path.basename(filePath) with
path.parse to strip the ".raw.spec.ts" suffix only when present, and compute
outputPath by joining path.dirname(filePath) with a safe filename (if the
basename ended with ".raw.spec.ts" replace that suffix with ".spec.ts",
otherwise append ".spec.ts" or require explicit options.output) before calling
writeFileSync; update the code around options.testName, filePath, outputPath,
and the writeFileSync call to use these path-based values to avoid platform
issues and accidental in-place overwrites.

In `@tools/test-recorder/src/index.ts`:
- Around line 58-60: Help text lists a --version flag that isn't implemented;
update tools/test-recorder/src/index.ts to either implement the flag handler or
remove it from the help output. Specifically, add argument parsing for
"--version" in the CLI entrypoint (index.ts) — e.g., detect process.argv
includes "--version" in the main startup logic (or the existing parseArgs/CLI
setup function) and print the package version (from package.json or a VERSION
constant) then exit with code 0; alternatively, if you don't want version
support, remove the --version line from the help generation so the advertised
option matches implemented behavior.
- Around line 33-40: The current check when required checks fail only logs
messages but doesn't set a non-zero exit code; update the failing branch that
checks the allPassed variable so it terminates the process with a non-zero exit
(e.g., call process.exit(1) or set process.exitCode = 1) after logging the error
messages in index.ts where the if (!allPassed) branch is defined to ensure
CI/automation detects failure.

In `@tools/test-recorder/src/pr/clipboard.ts`:
- Around line 4-36: The copyToClipboard function currently returns a bare
boolean which makes failures silent; update copyToClipboard to return structured
result or throw on failure: change its signature to return Promise<{ success:
boolean; platform: string; cmd?: string; code?: number; stderr?: string;
stdout?: string; error?: string }> (or throw an Error) and, where you call
spawnSync (for macos/windows and Linux xclip/xsel branches), capture and
propagate the child result details (status/code, stdout/stderr, command
attempted and platform) into the returned object or included in the thrown Error
message so callers can surface a clear fallback message; keep the existing
behavior of returning success=true when status===0.

In `@tools/test-recorder/src/pr/gh.ts`:
- Around line 45-89: The PR creation fails because the branch isn't pushed
before calling gh pr create; add a spawnSync('git', ['push', '--set-upstream',
'origin', branchName], {encoding:'utf-8', stdio:'pipe'}) call after the commit
step (after the commit variable/check and pass('Committed test file')) and
before invoking spawnSync for 'gh pr create'; check its .status like the other
git commands, call fail('Git push failed', push.stderr.trim()) and return {
success: false, error: push.stderr.trim() } on error, and call pass('Pushed
branch', branchName) on success so branchName, commit, and pr creation flow
match the existing error/success handling.

In `@tools/test-recorder/src/recorder/runner.ts`:
- Around line 98-137: Capture the return value of spawnSync(...) into a variable
(e.g., result) when invoking Playwright in the runner, then check result.error
and result.status !== 0 before printing the "Recording session complete" message
and returning success; if there is an error or a non-zero status,
log/console.error the failure with the result details and return { success:
false } (or otherwise abort) instead of proceeding to create rawOutputPath and
returning { success: true } so the caller (record.ts) won't continue to the
transform step on a failed Playwright run.
- Around line 23-30: findProjectRoot currently loops until dir === '/' which
breaks on Windows and can loop infinitely; change it to detect filesystem root
in a cross-platform way by comparing dir to path.dirname(dir) (use existsSync
and join as already used) and break/return null or throw if no
playwright.config.ts is found. For runRecording, after calling spawnSync (the
existing spawnSync invocation), inspect the returned result.status (and
result.error) and treat any non-zero status or error as failure: log/propagate
the stderr/output and return/throw a failing result instead of always returning
{ success: true }; reference the spawnSync call site and ensure runRecording
returns success only when result.status === 0 and no error is present.

In `@tools/test-recorder/src/recorder/template.ts`:
- Around line 24-26: The template currently interpolates options.workflow
directly into workflowLine which risks template injection or syntax errors if
the workflow name contains quotes/backticks; update the template generation in
template.ts so that the value passed to comfyPage.workflow.loadWorkflow is
safely escaped/serialized (e.g., use a safe string literal like
JSON.stringify(options.workflow) or an explicit escape function) rather than raw
interpolation, and ensure comfyPage.workflow.loadWorkflow(...) receives the
escaped/validated string.

In `@tools/test-recorder/src/transform/rules.ts`:
- Around line 104-120: The generated code interpolates raw user input into
single-quoted JS string literals (see variables tagStr, descName derived from
testName and tags in the wrap-in-describe transform), which breaks when inputs
contain apostrophes or backslashes; fix by escaping user strings before
interpolation — e.g., map tags and the computed descName through a sanitizer
that escapes backslashes and single quotes (or use a safe serializer like
JSON.stringify to produce properly-quoted string literals) and then use those
escaped values when building the template returned from the testMatch block so
the produced test.describe and tag array are syntactically valid.

In `@tools/test-recorder/tsconfig.json`:
- Around line 4-12: The compiled ESM output is producing extensionless relative
imports (because "moduleResolution": "bundler") which Node's ESM loader rejects
for the CLI entrypoint (dist/index.js) when package.json has "type": "module";
update tsconfig.json by replacing "moduleResolution": "bundler" with
"moduleResolution": "NodeNext" so tsc emits proper .js-extended imports, or
alternatively add explicit .js extensions to all relative imports used by the
codebase (e.g., imports like "./rules" and "../ui/logger") to ensure Node ESM
can resolve them.

---

Nitpick comments:
In `@browser_tests/AGENTS.md`:
- Around line 33-38: Update the "After Making Changes" checklist under the
"After Making Changes" heading to include the preferred local Playwright command
by adding a new bullet recommending `pnpm test:browser:local` so contributors
run the same default local E2E command used across the repo; ensure the entry
matches the style of the surrounding bullets and sits alongside the existing
`pnpm typecheck:browser`, `pnpm exec eslint`, and `pnpm exec oxlint` items.

In `@tools/test-recorder/package.json`:
- Around line 7-14: The package.json currently defines a "bin" entry for
"comfy-test" pointing to "./dist/index.js" but that dist artifact is never built
or used; either remove the unused "bin" field entirely, or add a "prepare" npm
script that runs the build so the CLI artifact exists when publishing (e.g.,
wire a "prepare" script to the existing "build" task), and ensure
"scripts.build" ("tsc") and the "comfy-test" bin name remain consistent if you
keep the bin entry.

In `@tools/test-recorder/src/checks/platform.ts`:
- Around line 8-15: The switch over os.platform() currently maps any
non-'darwin'/'win32' value to 'linux'; change the default case to return
'unknown' (or 'other') instead of 'linux' so unknown platforms aren't
misclassified, and update any call sites that consume this platform value to
handle 'unknown' by showing generic install instructions or prompting the user
for platform details; target the switch statement that inspects os.platform()
and modify the default branch and related platform-handling logic accordingly.

In `@tools/test-recorder/src/checks/python.ts`:
- Around line 10-11: The check uses inconsistent names for the same check across
success/failure branches (e.g., pass('Python', version) vs returning name:
'Python 3'); update all places in this file (including the pass() calls and the
returned result objects in both success and failure paths, e.g., where name is
set) to use one canonical check name (suggest "Python") so the pass('Python',
...) call and every return { name: ..., ok: ..., version } use the identical
string.

In `@tools/test-recorder/src/commands/record.ts`:
- Around line 35-42: The readMultiline Promise does not handle stream errors so
it can hang; update the readMultiline function (which uses createInterface and
rl) to attach an 'error' listener that rejects the Promise with the error, and
ensure the listener cleans up (e.g., calls rl.close() or removes listeners) to
avoid leaks; also consider listening to process.stdin 'error' or forwarding that
to the same rejection so any stdin error rejects the Promise instead of leaving
it unresolved.

In `@tools/test-recorder/src/pr/gh.ts`:
- Around line 17-36: The function checkGhAvailable is declared async but only
uses synchronous execSync calls; remove the async keyword to avoid misleading
the API or refactor to use asynchronous child_process methods (e.g., promisified
exec or spawn) instead. Locate checkGhAvailable and replace the declaration to
be a plain synchronous function (remove async) or change the execSync calls to
async equivalents (promisified exec/child_process.spawn wrapped in promises),
ensuring returned object shape ({ available, authenticated }) and error handling
remain the same.
- Around line 17-36: The checkGhAvailable() implementation duplicates logic from
checkGh(); replace its body by reusing the existing checkGh() helper or extract
a shared helper that runs "gh --version" and "gh auth status" so both checkGh()
and checkGhAvailable() call it; update imports to bring in checkGh() (or the new
shared helper), adapt return shape if needed to match {available:boolean,
authenticated:boolean}, and remove the duplicated execSync calls inside
checkGhAvailable().

In `@tools/test-recorder/src/pr/manual.ts`:
- Line 20: The template currently inserts options.relativePath directly;
normalize it to forward slashes before display by replacing backslashes with
slashes (e.g., transform options.relativePath via a replace of "\\" with "/")
where the template contains `${options.relativePath}` in the exported function
in manual.ts so the displayed path is always forward-slash normalized.

In `@tools/test-recorder/src/ui/logger.ts`:
- Around line 18-20: The function wait is declared but unused; either remove the
unused function wait from the module to clean up dead code, or if it was
intended for external use, export it (e.g., add an export for wait) and ensure
callers/imports are updated; update any related tests or imports to reflect the
removal or exported symbol so the logger module has no unused declarations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 221c6942-242a-4b71-a109-7cb7e8b0752c

📥 Commits

Reviewing files that changed from the base of the PR and between 4821910 and 054e4cf.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (44)
  • .claude/agents/playwright-test-generator.md
  • .claude/agents/playwright-test-healer.md
  • .claude/agents/playwright-test-planner.md
  • .claude/skills/codegen-transform/SKILL.md
  • .mcp.json
  • .oxlintrc.json
  • AGENTS.md
  • browser_tests/AGENTS.md
  • browser_tests/README.md
  • browser_tests/specs/README.md
  • browser_tests/tests/seed.spec.ts
  • knip.config.ts
  • package.json
  • pnpm-workspace.yaml
  • scripts/patch-playwright-agents.js
  • scripts/update-playwright-agents.sh
  • tools/test-recorder/README.md
  • tools/test-recorder/package.json
  • tools/test-recorder/src/checks/backend.ts
  • tools/test-recorder/src/checks/devServer.ts
  • tools/test-recorder/src/checks/gh.ts
  • tools/test-recorder/src/checks/git.ts
  • tools/test-recorder/src/checks/node.ts
  • tools/test-recorder/src/checks/platform.ts
  • tools/test-recorder/src/checks/playwright.ts
  • tools/test-recorder/src/checks/pnpm.ts
  • tools/test-recorder/src/checks/python.ts
  • tools/test-recorder/src/checks/types.ts
  • tools/test-recorder/src/checks/xcode.ts
  • tools/test-recorder/src/commands/check.ts
  • tools/test-recorder/src/commands/list.ts
  • tools/test-recorder/src/commands/record.ts
  • tools/test-recorder/src/commands/transform.ts
  • tools/test-recorder/src/index.ts
  • tools/test-recorder/src/pr/clipboard.ts
  • tools/test-recorder/src/pr/gh.ts
  • tools/test-recorder/src/pr/manual.ts
  • tools/test-recorder/src/recorder/runner.ts
  • tools/test-recorder/src/recorder/template.ts
  • tools/test-recorder/src/transform/engine.ts
  • tools/test-recorder/src/transform/rules.ts
  • tools/test-recorder/src/ui/logger.ts
  • tools/test-recorder/src/ui/steps.ts
  • tools/test-recorder/tsconfig.json

Merge latest main into playwright-test-agents-system branch.
Resolve conflicts in knip.config.ts and pnpm-lock.yaml.
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 29, 2026

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 03/30/2026, 12:49:30 AM UTC

Links

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 29, 2026

🎭 Playwright: ✅ 833 passed, 0 failed · 6 flaky

📊 Browser Reports
  • chromium: View Report (✅ 819 / ❌ 0 / ⚠️ 6 / ⏭️ 1)
  • chromium-2x: View Report (✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • chromium-0.5x: View Report (✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • mobile-chrome: View Report (✅ 11 / ❌ 0 / ⚠️ 0 / ⏭️ 0)

@socket-security
Copy link
Copy Markdown

socket-security bot commented Mar 29, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​clack/​prompts@​0.9.11001009995100

View full report

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 29, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 29, 2026

📦 Bundle: 5.09 MB gzip 🟢 -37 B

Details

Summary

  • Raw size: 23.5 MB baseline 23.5 MB — ⚪ 0 B
  • Gzip: 5.09 MB baseline 5.09 MB — 🟢 -37 B
  • Brotli: 3.94 MB baseline 3.94 MB — 🔴 +62 B
  • Bundles: 249 current • 249 baseline • 114 added / 114 removed

Category Glance
Vendor & Third-Party ⚪ 0 B (9.8 MB) · Other ⚪ 0 B (8.45 MB) · Data & Services ⚪ 0 B (2.96 MB) · Graph Workspace ⚪ 0 B (1.14 MB) · Panels & Settings ⚪ 0 B (484 kB) · Utilities & Hooks ⚪ 0 B (334 kB) · + 5 more

App Entry Points — 22.3 kB (baseline 22.3 kB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-8NRe2leU.js (removed) 22.3 kB 🟢 -22.3 kB 🟢 -7.93 kB 🟢 -6.79 kB
assets/index-DAk0CFZT.js (new) 22.3 kB 🔴 +22.3 kB 🔴 +7.94 kB 🔴 +6.8 kB

Status: 1 added / 1 removed

Graph Workspace — 1.14 MB (baseline 1.14 MB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-BeUCNdtg.js (removed) 1.14 MB 🟢 -1.14 MB 🟢 -244 kB 🟢 -184 kB
assets/GraphView-Czi9OlkY.js (new) 1.14 MB 🔴 +1.14 MB 🔴 +244 kB 🔴 +184 kB

Status: 1 added / 1 removed

Views & Navigation — 76.6 kB (baseline 76.6 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-CJaH1Ahv.js (new) 15.7 kB 🔴 +15.7 kB 🔴 +3.39 kB 🔴 +2.9 kB
assets/CloudSurveyView-DzDZaGGo.js (removed) 15.7 kB 🟢 -15.7 kB 🟢 -3.39 kB 🟢 -2.9 kB
assets/CloudLoginView-BCdRuRAy.js (new) 12 kB 🔴 +12 kB 🔴 +3.35 kB 🔴 +2.96 kB
assets/CloudLoginView-BIXnNTMG.js (removed) 12 kB 🟢 -12 kB 🟢 -3.36 kB 🟢 -2.97 kB
assets/CloudSignupView-B2M71p4S.js (new) 9.78 kB 🔴 +9.78 kB 🔴 +2.85 kB 🔴 +2.5 kB
assets/CloudSignupView-DEwTU_9d.js (removed) 9.78 kB 🟢 -9.78 kB 🟢 -2.85 kB 🟢 -2.5 kB
assets/UserCheckView-BwN2tkCt.js (new) 9.04 kB 🔴 +9.04 kB 🔴 +2.33 kB 🔴 +2.03 kB
assets/UserCheckView-CF1L4GMp.js (removed) 9.04 kB 🟢 -9.04 kB 🟢 -2.33 kB 🟢 -2.03 kB
assets/CloudLayoutView-CaUdVnlg.js (new) 7.54 kB 🔴 +7.54 kB 🔴 +2.36 kB 🔴 +2.05 kB
assets/CloudLayoutView-rA6-7-y8.js (removed) 7.54 kB 🟢 -7.54 kB 🟢 -2.36 kB 🟢 -2.08 kB
assets/CloudForgotPasswordView-CANGt9eX.js (new) 5.94 kB 🔴 +5.94 kB 🔴 +2.09 kB 🔴 +1.85 kB
assets/CloudForgotPasswordView-DHsU0DUh.js (removed) 5.94 kB 🟢 -5.94 kB 🟢 -2.09 kB 🟢 -1.85 kB
assets/CloudAuthTimeoutView-CEeKpd50.js (removed) 5.31 kB 🟢 -5.31 kB 🟢 -1.93 kB 🟢 -1.68 kB
assets/CloudAuthTimeoutView-D8OU9u36.js (new) 5.31 kB 🔴 +5.31 kB 🔴 +1.93 kB 🔴 +1.7 kB
assets/CloudSubscriptionRedirectView-9RqmCY1d.js (removed) 5.08 kB 🟢 -5.08 kB 🟢 -1.91 kB 🟢 -1.69 kB
assets/CloudSubscriptionRedirectView-DHOk-DAQ.js (new) 5.08 kB 🔴 +5.08 kB 🔴 +1.91 kB 🔴 +1.69 kB
assets/UserSelectView-4VzZ-Ux3.js (new) 4.71 kB 🔴 +4.71 kB 🔴 +1.74 kB 🔴 +1.54 kB
assets/UserSelectView-tICly9ED.js (removed) 4.71 kB 🟢 -4.71 kB 🟢 -1.74 kB 🟢 -1.54 kB

Status: 9 added / 9 removed / 2 unchanged

Panels & Settings — 484 kB (baseline 484 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/KeybindingPanel-CcjLJAea.js (new) 46.6 kB 🔴 +46.6 kB 🔴 +9.52 kB 🔴 +8.47 kB
assets/KeybindingPanel-DxV0DtgP.js (removed) 46.6 kB 🟢 -46.6 kB 🟢 -9.52 kB 🟢 -8.47 kB
assets/SecretsPanel-DL0cBF6i.js (removed) 22.4 kB 🟢 -22.4 kB 🟢 -5.42 kB 🟢 -4.76 kB
assets/SecretsPanel-Dn4fBtQT.js (new) 22.4 kB 🔴 +22.4 kB 🔴 +5.42 kB 🔴 +4.76 kB
assets/LegacyCreditsPanel-CLJ4U9R4.js (new) 21.5 kB 🔴 +21.5 kB 🔴 +5.82 kB 🔴 +5.13 kB
assets/LegacyCreditsPanel-CMkC6o06.js (removed) 21.5 kB 🟢 -21.5 kB 🟢 -5.81 kB 🟢 -5.13 kB
assets/SubscriptionPanel-7Z1Elfjx.js (new) 19.7 kB 🔴 +19.7 kB 🔴 +5.01 kB 🔴 +4.41 kB
assets/SubscriptionPanel-Bf964JXT.js (removed) 19.7 kB 🟢 -19.7 kB 🟢 -5.01 kB 🟢 -4.42 kB
assets/AboutPanel-CTq8aYZ5.js (removed) 12 kB 🟢 -12 kB 🟢 -3.33 kB 🟢 -2.98 kB
assets/AboutPanel-FvKKOs6b.js (new) 12 kB 🔴 +12 kB 🔴 +3.32 kB 🔴 +2.99 kB
assets/ExtensionPanel-Cxkknrz8.js (removed) 9.78 kB 🟢 -9.78 kB 🟢 -2.82 kB 🟢 -2.49 kB
assets/ExtensionPanel-GdX3dfJ2.js (new) 9.78 kB 🔴 +9.78 kB 🔴 +2.82 kB 🔴 +2.51 kB
assets/ServerConfigPanel-BImOE9wI.js (new) 6.85 kB 🔴 +6.85 kB 🔴 +2.27 kB 🔴 +2.02 kB
assets/ServerConfigPanel-C19uXxsm.js (removed) 6.85 kB 🟢 -6.85 kB 🟢 -2.28 kB 🟢 -2.04 kB
assets/UserPanel-CBxHFwIx.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +2.15 kB 🔴 +1.89 kB
assets/UserPanel-DWY_xr8y.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -2.15 kB 🟢 -1.89 kB
assets/cloudRemoteConfig-DF6OoXX7.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -901 B 🟢 -797 B
assets/cloudRemoteConfig-yyTxybMK.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +903 B 🔴 +795 B
assets/refreshRemoteConfig-BLf65E-U.js (new) 1.45 kB 🔴 +1.45 kB 🔴 +650 B 🔴 +554 B
assets/refreshRemoteConfig-CYmykEAM.js (removed) 1.45 kB 🟢 -1.45 kB 🟢 -648 B 🟢 -549 B

Status: 10 added / 10 removed / 12 unchanged

User & Accounts — 17.1 kB (baseline 17.1 kB) • ⚪ 0 B

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-C03zoMda.js (new) 3.57 kB 🔴 +3.57 kB 🔴 +1.26 kB 🔴 +1.08 kB
assets/auth-CPlUer_B.js (removed) 3.57 kB 🟢 -3.57 kB 🟢 -1.26 kB 🟢 -1.08 kB
assets/SignUpForm-CT1k2zHd.js (new) 3.16 kB 🔴 +3.16 kB 🔴 +1.28 kB 🔴 +1.15 kB
assets/SignUpForm-xlDr62ip.js (removed) 3.16 kB 🟢 -3.16 kB 🟢 -1.28 kB 🟢 -1.14 kB
assets/UpdatePasswordContent-9cBcxA23.js (removed) 2.66 kB 🟢 -2.66 kB 🟢 -1.19 kB 🟢 -1.06 kB
assets/UpdatePasswordContent-BVE0uMEE.js (new) 2.66 kB 🔴 +2.66 kB 🔴 +1.19 kB 🔴 +1.05 kB
assets/authStore-BP6Qupnz.js (removed) 989 B 🟢 -989 B 🟢 -483 B 🟢 -426 B
assets/authStore-DCNq7ghQ.js (new) 989 B 🔴 +989 B 🔴 +478 B 🔴 +426 B
assets/auth-D2saAXnJ.js (new) 348 B 🔴 +348 B 🔴 +215 B 🔴 +185 B
assets/auth-zpx6eQ29.js (removed) 348 B 🟢 -348 B 🟢 -215 B 🟢 -193 B

Status: 5 added / 5 removed / 2 unchanged

Editors & Dialogs — 109 kB (baseline 109 kB) • ⚪ 0 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useShareDialog-B3PU17Mc.js (new) 108 kB 🔴 +108 kB 🔴 +22.4 kB 🔴 +18.9 kB
assets/useShareDialog-BA_OR3FV.js (removed) 108 kB 🟢 -108 kB 🟢 -22.4 kB 🟢 -18.9 kB
assets/useSubscriptionDialog-DYPqEe5S.js (new) 969 B 🔴 +969 B 🔴 +472 B 🔴 +413 B
assets/useSubscriptionDialog-XKnUFp6b.js (removed) 969 B 🟢 -969 B 🟢 -477 B 🟢 -413 B

Status: 2 added / 2 removed

UI Components — 60.3 kB (baseline 60.3 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton--sxFwCoj.js (removed) 13.5 kB 🟢 -13.5 kB 🟢 -3.79 kB 🟢 -3.37 kB
assets/ComfyQueueButton-DMQ3S6Nt.js (new) 13.5 kB 🔴 +13.5 kB 🔴 +3.79 kB 🔴 +3.38 kB
assets/useTerminalTabs-B0iIW4PM.js (new) 10.7 kB 🔴 +10.7 kB 🔴 +3.6 kB 🔴 +3.17 kB
assets/useTerminalTabs-D_VTHfoL.js (removed) 10.7 kB 🟢 -10.7 kB 🟢 -3.6 kB 🟢 -3.16 kB
assets/SubscribeButton-0UwzxnwU.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.04 kB 🟢 -911 B
assets/SubscribeButton-CGrPBHes.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.04 kB 🔴 +914 B
assets/cloudFeedbackTopbarButton-CF9iwsPQ.js (removed) 1.66 kB 🟢 -1.66 kB 🟢 -844 B 🟢 -765 B
assets/cloudFeedbackTopbarButton-CfMhAany.js (new) 1.66 kB 🔴 +1.66 kB 🔴 +842 B 🔴 +742 B
assets/ComfyQueueButton-Bms7z0E7.js (removed) 1.03 kB 🟢 -1.03 kB 🟢 -489 B 🟢 -436 B
assets/ComfyQueueButton-DvICQ-TK.js (new) 1.03 kB 🔴 +1.03 kB 🔴 +488 B 🔴 +438 B

Status: 5 added / 5 removed / 8 unchanged

Data & Services — 2.96 MB (baseline 2.96 MB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-B8X4q8Si.js (new) 1.92 MB 🔴 +1.92 MB 🔴 +443 kB 🔴 +336 kB
assets/dialogService-CbuLmw17.js (removed) 1.92 MB 🟢 -1.92 MB 🟢 -443 kB 🟢 -336 kB
assets/api-32F7tDZ4.js (removed) 885 kB 🟢 -885 kB 🟢 -211 kB 🟢 -167 kB
assets/api-BNuRNRTJ.js (new) 885 kB 🔴 +885 kB 🔴 +211 kB 🔴 +167 kB
assets/load3dService-Bw7-UgPa.js (removed) 92.5 kB 🟢 -92.5 kB 🟢 -19.7 kB 🟢 -17 kB
assets/load3dService-lOgmf5GY.js (new) 92.5 kB 🔴 +92.5 kB 🔴 +19.7 kB 🔴 +16.9 kB
assets/workflowShareService-DaCwwYOo.js (new) 16.6 kB 🔴 +16.6 kB 🔴 +4.88 kB 🔴 +4.32 kB
assets/workflowShareService-vlKL6o4A.js (removed) 16.6 kB 🟢 -16.6 kB 🟢 -4.88 kB 🟢 -4.32 kB
assets/keybindingService-D2OUF9gC.js (removed) 13.8 kB 🟢 -13.8 kB 🟢 -3.67 kB 🟢 -3.21 kB
assets/keybindingService-D83WF0LG.js (new) 13.8 kB 🔴 +13.8 kB 🔴 +3.67 kB 🔴 +3.21 kB
assets/releaseStore-BZCCYmUF.js (new) 8.12 kB 🔴 +8.12 kB 🔴 +2.28 kB 🔴 +2 kB
assets/releaseStore-Dkd-yYIg.js (removed) 8.12 kB 🟢 -8.12 kB 🟢 -2.28 kB 🟢 -2 kB
assets/userStore-Bfm6qLNy.js (new) 2.24 kB 🔴 +2.24 kB 🔴 +869 B 🔴 +767 B
assets/userStore-C9JgarYM.js (removed) 2.24 kB 🟢 -2.24 kB 🟢 -871 B 🟢 -769 B
assets/audioService-CDheJ4JS.js (removed) 1.8 kB 🟢 -1.8 kB 🟢 -879 B 🟢 -763 B
assets/audioService-rW7wul7K.js (new) 1.8 kB 🔴 +1.8 kB 🔴 +879 B 🔴 +764 B
assets/releaseStore-C3qGVf16.js (new) 993 B 🔴 +993 B 🔴 +479 B 🔴 +427 B
assets/releaseStore-D_RmteAT.js (removed) 993 B 🟢 -993 B 🟢 -481 B 🟢 -424 B
assets/workflowDraftStore-BCyNPN04.js (new) 969 B 🔴 +969 B 🔴 +471 B 🔴 +421 B
assets/workflowDraftStore-DzBZOaFS.js (removed) 969 B 🟢 -969 B 🟢 -476 B 🟢 -420 B
assets/dialogService-Cfah_6q_.js (new) 958 B 🔴 +958 B 🔴 +463 B 🔴 +414 B
assets/dialogService-CoDqjO7z.js (removed) 958 B 🟢 -958 B 🟢 -468 B 🟢 -411 B
assets/settingStore-C4DAmrki.js (new) 956 B 🔴 +956 B 🔴 +467 B 🔴 +413 B
assets/settingStore-CWxVK2hA.js (removed) 956 B 🟢 -956 B 🟢 -471 B 🟢 -413 B
assets/assetsStore-CxDBpxZq.js (new) 955 B 🔴 +955 B 🔴 +467 B 🔴 +414 B
assets/assetsStore-DItLr89d.js (removed) 955 B 🟢 -955 B 🟢 -473 B 🟢 -416 B

Status: 13 added / 13 removed / 4 unchanged

Utilities & Hooks — 334 kB (baseline 334 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useConflictDetection-BKIiV6TF.js (removed) 232 kB 🟢 -232 kB 🟢 -51.3 kB 🟢 -41.7 kB
assets/useConflictDetection-BNnz1JDM.js (new) 232 kB 🔴 +232 kB 🔴 +51.3 kB 🔴 +41.8 kB
assets/useLoad3dViewer-8V5lHDmO.js (removed) 18.7 kB 🟢 -18.7 kB 🟢 -4.43 kB 🟢 -3.91 kB
assets/useLoad3dViewer-K4wadiqm.js (new) 18.7 kB 🔴 +18.7 kB 🔴 +4.43 kB 🔴 +3.88 kB
assets/useLoad3d-BnUHUxjX.js (removed) 15 kB 🟢 -15 kB 🟢 -3.79 kB 🟢 -3.35 kB
assets/useLoad3d-DPhyp2eL.js (new) 15 kB 🔴 +15 kB 🔴 +3.79 kB 🔴 +3.35 kB
assets/useFeatureFlags-CR3pf54M.js (removed) 5.78 kB 🟢 -5.78 kB 🟢 -1.75 kB 🟢 -1.49 kB
assets/useFeatureFlags-DY27renb.js (new) 5.78 kB 🔴 +5.78 kB 🔴 +1.75 kB 🔴 +1.49 kB
assets/useCopyToClipboard-BzqUk78N.js (removed) 5.29 kB 🟢 -5.29 kB 🟢 -1.86 kB 🟢 -1.57 kB
assets/useCopyToClipboard-DKji_wdZ.js (new) 5.29 kB 🔴 +5.29 kB 🔴 +1.86 kB 🔴 +1.57 kB
assets/useWorkspaceUI-B16vY8B2.js (removed) 3.34 kB 🟢 -3.34 kB 🟢 -981 B 🟢 -811 B
assets/useWorkspaceUI-DDBszrFB.js (new) 3.34 kB 🔴 +3.34 kB 🔴 +981 B 🔴 +812 B
assets/subscriptionCheckoutUtil-BuHeJt4L.js (removed) 2.97 kB 🟢 -2.97 kB 🟢 -1.31 kB 🟢 -1.14 kB
assets/subscriptionCheckoutUtil-DpYfhK8S.js (new) 2.97 kB 🔴 +2.97 kB 🔴 +1.31 kB 🔴 +1.14 kB
assets/assetPreviewUtil-7EK073IR.js (removed) 2.27 kB 🟢 -2.27 kB 🟢 -959 B 🟢 -837 B
assets/assetPreviewUtil-l-O74NWk.js (new) 2.27 kB 🔴 +2.27 kB 🔴 +959 B 🔴 +833 B
assets/useUpstreamValue-BmoJ-_lP.js (removed) 2.08 kB 🟢 -2.08 kB 🟢 -805 B 🟢 -718 B
assets/useUpstreamValue-E3AQmRB7.js (new) 2.08 kB 🔴 +2.08 kB 🔴 +806 B 🔴 +721 B
assets/useLoad3d-By0NGCg5.js (new) 1.13 kB 🔴 +1.13 kB 🔴 +538 B 🔴 +483 B
assets/useLoad3d-iZWZvxkT.js (removed) 1.13 kB 🟢 -1.13 kB 🟢 -540 B 🟢 -479 B
assets/useLoad3dViewer-DHuD9BH4.js (new) 1.07 kB 🔴 +1.07 kB 🔴 +504 B 🔴 +453 B
assets/useLoad3dViewer-DTAzULLv.js (removed) 1.07 kB 🟢 -1.07 kB 🟢 -506 B 🟢 -453 B
assets/useCurrentUser-_4yt8mVk.js (new) 955 B 🔴 +955 B 🔴 +467 B 🔴 +414 B
assets/useCurrentUser-BP32zLqq.js (removed) 955 B 🟢 -955 B 🟢 -472 B 🟢 -411 B
assets/useWorkspaceSwitch-BCCq1hjf.js (new) 747 B 🔴 +747 B 🔴 +387 B 🔴 +335 B
assets/useWorkspaceSwitch-CpVuaQm8.js (removed) 747 B 🟢 -747 B 🟢 -386 B 🟢 -335 B

Status: 13 added / 13 removed / 12 unchanged

Vendor & Third-Party — 9.8 MB (baseline 9.8 MB) • ⚪ 0 B

External libraries and shared vendor chunks

Status: 16 unchanged

Other — 8.45 MB (baseline 8.45 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-Dl7-Eo6P.js (new) 76.8 kB 🔴 +76.8 kB 🔴 +19.9 kB 🔴 +16.9 kB
assets/core-h-gxmFRi.js (removed) 76.8 kB 🟢 -76.8 kB 🟢 -19.9 kB 🟢 -17 kB
assets/groupNode-BI7XUsA3.js (removed) 74 kB 🟢 -74 kB 🟢 -18.5 kB 🟢 -16.3 kB
assets/groupNode-C6IGwHty.js (new) 74 kB 🔴 +74 kB 🔴 +18.5 kB 🔴 +16.3 kB
assets/WidgetSelect-BPGE1YLi.js (removed) 64.6 kB 🟢 -64.6 kB 🟢 -14.1 kB 🟢 -12.2 kB
assets/WidgetSelect-DUShcvDX.js (new) 64.6 kB 🔴 +64.6 kB 🔴 +14.1 kB 🔴 +12.2 kB
assets/SubscriptionRequiredDialogContentWorkspace-BHo3AUvY.js (new) 48.9 kB 🔴 +48.9 kB 🔴 +9.29 kB 🔴 +7.96 kB
assets/SubscriptionRequiredDialogContentWorkspace-BNzTE43J.js (removed) 48.9 kB 🟢 -48.9 kB 🟢 -9.29 kB 🟢 -7.96 kB
assets/WidgetPainter-B7-XujHr.js (new) 33.3 kB 🔴 +33.3 kB 🔴 +8.11 kB 🔴 +7.2 kB
assets/WidgetPainter-I9bcncbu.js (removed) 33.3 kB 🟢 -33.3 kB 🟢 -8.11 kB 🟢 -7.21 kB
assets/Load3DControls-CfdKRBVc.js (removed) 32.1 kB 🟢 -32.1 kB 🟢 -5.47 kB 🟢 -4.75 kB
assets/Load3DControls-W9ZOrvH4.js (new) 32.1 kB 🔴 +32.1 kB 🔴 +5.47 kB 🔴 +4.77 kB
assets/WorkspacePanelContent-Bs8g6gif.js (removed) 29.9 kB 🟢 -29.9 kB 🟢 -6.33 kB 🟢 -5.55 kB
assets/WorkspacePanelContent-DAQBmEzr.js (new) 29.9 kB 🔴 +29.9 kB 🔴 +6.33 kB 🔴 +5.55 kB
assets/SubscriptionRequiredDialogContent-BpiWYyjH.js (new) 28.2 kB 🔴 +28.2 kB 🔴 +7.17 kB 🔴 +6.31 kB
assets/SubscriptionRequiredDialogContent-DDz1JGAC.js (removed) 28.2 kB 🟢 -28.2 kB 🟢 -7.16 kB 🟢 -6.3 kB
assets/Load3dViewerContent-Bn1zApU2.js (removed) 24.3 kB 🟢 -24.3 kB 🟢 -5.32 kB 🟢 -4.63 kB
assets/Load3dViewerContent-C1WRa_Xt.js (new) 24.3 kB 🔴 +24.3 kB 🔴 +5.32 kB 🔴 +4.63 kB
assets/WidgetImageCrop-DUYm3yIn.js (new) 23.3 kB 🔴 +23.3 kB 🔴 +5.83 kB 🔴 +5.14 kB
assets/WidgetImageCrop-i5NGMcSO.js (removed) 23.3 kB 🟢 -23.3 kB 🟢 -5.83 kB 🟢 -5.13 kB
assets/SubscriptionPanelContentWorkspace-B8s8PFcD.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +5.18 kB 🔴 +4.55 kB
assets/SubscriptionPanelContentWorkspace-BHRcLX8d.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -5.18 kB 🟢 -4.56 kB
assets/SignInContent-7brBmIRQ.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.29 kB 🔴 +4.62 kB
assets/SignInContent-DaH8N98M.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.29 kB 🟢 -4.64 kB
assets/CurrentUserPopoverWorkspace-Bi5yBKMM.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +4.84 kB 🔴 +4.32 kB
assets/CurrentUserPopoverWorkspace-DuO1BA52.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -4.83 kB 🟢 -4.33 kB
assets/WidgetInputNumber-CDbniFT0.js (removed) 19.1 kB 🟢 -19.1 kB 🟢 -4.83 kB 🟢 -4.29 kB
assets/WidgetInputNumber-mrm2OiUP.js (new) 19.1 kB 🔴 +19.1 kB 🔴 +4.84 kB 🔴 +4.3 kB
assets/WidgetRecordAudio-CioEFe6y.js (removed) 18.1 kB 🟢 -18.1 kB 🟢 -5.18 kB 🟢 -4.64 kB
assets/WidgetRecordAudio-DlEijL1d.js (new) 18.1 kB 🔴 +18.1 kB 🔴 +5.18 kB 🔴 +4.64 kB
assets/Load3D-BIu5FMAY.js (new) 16.9 kB 🔴 +16.9 kB 🔴 +4.12 kB 🔴 +3.59 kB
assets/Load3D-CPHY7sDp.js (removed) 16.9 kB 🟢 -16.9 kB 🟢 -4.12 kB 🟢 -3.59 kB
assets/WidgetCurve-B5USOhK6.js (new) 16.1 kB 🔴 +16.1 kB 🔴 +4.97 kB 🔴 +4.46 kB
assets/WidgetCurve-DS-1xtst.js (removed) 16.1 kB 🟢 -16.1 kB 🟢 -4.97 kB 🟢 -4.46 kB
assets/load3d-0hK3Z4He.js (removed) 15 kB 🟢 -15 kB 🟢 -4.32 kB 🟢 -3.75 kB
assets/load3d-KHynXN5t.js (new) 15 kB 🔴 +15 kB 🔴 +4.32 kB 🔴 +3.75 kB
assets/WaveAudioPlayer-DeqUke5G.js (removed) 13.4 kB 🟢 -13.4 kB 🟢 -3.68 kB 🟢 -3.22 kB
assets/WaveAudioPlayer-DnvOVIck.js (new) 13.4 kB 🔴 +13.4 kB 🔴 +3.68 kB 🔴 +3.22 kB
assets/TeamWorkspacesDialogContent-DBIDdGIp.js (removed) 11.1 kB 🟢 -11.1 kB 🟢 -3.33 kB 🟢 -2.97 kB
assets/TeamWorkspacesDialogContent-DpaUak0m.js (new) 11.1 kB 🔴 +11.1 kB 🔴 +3.33 kB 🔴 +2.98 kB
assets/nodeTemplates-B3k2CkFI.js (removed) 9.58 kB 🟢 -9.58 kB 🟢 -3.37 kB 🟢 -2.96 kB
assets/nodeTemplates-FbDjiSsK.js (new) 9.58 kB 🔴 +9.58 kB 🔴 +3.37 kB 🔴 +2.96 kB
assets/InviteMemberDialogContent-DZRbYlJh.js (new) 7.77 kB 🔴 +7.77 kB 🔴 +2.45 kB 🔴 +2.13 kB
assets/InviteMemberDialogContent-DzttBhf-.js (removed) 7.77 kB 🟢 -7.77 kB 🟢 -2.45 kB 🟢 -2.13 kB
assets/Load3DConfiguration-8wLR-KZC.js (removed) 6.6 kB 🟢 -6.6 kB 🟢 -2.04 kB 🟢 -1.78 kB
assets/Load3DConfiguration-BO408Xek.js (new) 6.6 kB 🔴 +6.6 kB 🔴 +2.04 kB 🔴 +1.78 kB
assets/onboardingCloudRoutes-D8C9uTLS.js (removed) 6.53 kB 🟢 -6.53 kB 🟢 -2.04 kB 🟢 -1.75 kB
assets/onboardingCloudRoutes-DgPtkBDq.js (new) 6.53 kB 🔴 +6.53 kB 🔴 +2.04 kB 🔴 +1.76 kB
assets/WidgetWithControl-C3Gy0sau.js (new) 5.99 kB 🔴 +5.99 kB 🔴 +2.38 kB 🔴 +2.13 kB
assets/WidgetWithControl-CnEagfqO.js (removed) 5.99 kB 🟢 -5.99 kB 🟢 -2.38 kB 🟢 -2.11 kB
assets/CreateWorkspaceDialogContent-aCQEhqwm.js (removed) 5.95 kB 🟢 -5.95 kB 🟢 -2.15 kB 🟢 -1.87 kB
assets/CreateWorkspaceDialogContent-CYztbarK.js (new) 5.95 kB 🔴 +5.95 kB 🔴 +2.15 kB 🔴 +1.88 kB
assets/FreeTierDialogContent-Bd5H_mcX.js (new) 5.82 kB 🔴 +5.82 kB 🔴 +2.04 kB 🔴 +1.81 kB
assets/FreeTierDialogContent-DkFznB4Y.js (removed) 5.82 kB 🟢 -5.82 kB 🟢 -2.05 kB 🟢 -1.81 kB
assets/EditWorkspaceDialogContent-52oJnahv.js (new) 5.75 kB 🔴 +5.75 kB 🔴 +2.11 kB 🔴 +1.85 kB
assets/EditWorkspaceDialogContent-BS-Qe77w.js (removed) 5.75 kB 🟢 -5.75 kB 🟢 -2.11 kB 🟢 -1.84 kB
assets/WidgetTextarea-BWs4PYzF.js (new) 5.53 kB 🔴 +5.53 kB 🔴 +2.17 kB 🔴 +1.93 kB
assets/WidgetTextarea-paW2VRLX.js (removed) 5.53 kB 🟢 -5.53 kB 🟢 -2.17 kB 🟢 -1.92 kB
assets/Preview3d-BBa-hUpn.js (removed) 5.36 kB 🟢 -5.36 kB 🟢 -1.79 kB 🟢 -1.56 kB
assets/Preview3d-Ce4iSGeM.js (new) 5.36 kB 🔴 +5.36 kB 🔴 +1.79 kB 🔴 +1.56 kB
assets/ValueControlPopover-BeRcXnfe.js (removed) 5.33 kB 🟢 -5.33 kB 🟢 -1.93 kB 🟢 -1.73 kB
assets/ValueControlPopover-CIqAsoOL.js (new) 5.33 kB 🔴 +5.33 kB 🔴 +1.93 kB 🔴 +1.73 kB
assets/CancelSubscriptionDialogContent-C8k5BO_r.js (new) 5.22 kB 🔴 +5.22 kB 🔴 +1.95 kB 🔴 +1.71 kB
assets/CancelSubscriptionDialogContent-DIAgOZGm.js (removed) 5.22 kB 🟢 -5.22 kB 🟢 -1.95 kB 🟢 -1.7 kB
assets/DeleteWorkspaceDialogContent-Dhab_2Es.js (new) 4.65 kB 🔴 +4.65 kB 🔴 +1.79 kB 🔴 +1.56 kB
assets/DeleteWorkspaceDialogContent-DSZpTgOq.js (removed) 4.65 kB 🟢 -4.65 kB 🟢 -1.79 kB 🟢 -1.55 kB
assets/LeaveWorkspaceDialogContent-D-GH8pLW.js (new) 4.48 kB 🔴 +4.48 kB 🔴 +1.74 kB 🔴 +1.51 kB
assets/LeaveWorkspaceDialogContent-HhcTHcp4.js (removed) 4.48 kB 🟢 -4.48 kB 🟢 -1.74 kB 🟢 -1.5 kB
assets/RemoveMemberDialogContent-B6ESowm8.js (removed) 4.46 kB 🟢 -4.46 kB 🟢 -1.69 kB 🟢 -1.47 kB
assets/RemoveMemberDialogContent-Cgo4L0l_.js (new) 4.46 kB 🔴 +4.46 kB 🔴 +1.69 kB 🔴 +1.47 kB
assets/tierBenefits-BF0fBeYJ.js (removed) 4.45 kB 🟢 -4.45 kB 🟢 -1.57 kB 🟢 -1.36 kB
assets/tierBenefits-BnWZfzkd.js (new) 4.45 kB 🔴 +4.45 kB 🔴 +1.58 kB 🔴 +1.36 kB
assets/RevokeInviteDialogContent-BraIeVE9.js (new) 4.37 kB 🔴 +4.37 kB 🔴 +1.7 kB 🔴 +1.49 kB
assets/RevokeInviteDialogContent-CnaSqOOi.js (removed) 4.37 kB 🟢 -4.37 kB 🟢 -1.7 kB 🟢 -1.48 kB
assets/InviteMemberUpsellDialogContent-7vTXfv-t.js (removed) 4.27 kB 🟢 -4.27 kB 🟢 -1.56 kB 🟢 -1.37 kB
assets/InviteMemberUpsellDialogContent-ownBOFvm.js (new) 4.27 kB 🔴 +4.27 kB 🔴 +1.56 kB 🔴 +1.37 kB
assets/cloudSessionCookie-BIYvRetC.js (removed) 4.12 kB 🟢 -4.12 kB 🟢 -1.49 kB 🟢 -1.29 kB
assets/cloudSessionCookie-f7eBWrK6.js (new) 4.12 kB 🔴 +4.12 kB 🔴 +1.48 kB 🔴 +1.29 kB
assets/saveMesh-C19qoWF9.js (removed) 3.92 kB 🟢 -3.92 kB 🟢 -1.69 kB 🟢 -1.48 kB
assets/saveMesh-D6KwCeQA.js (new) 3.92 kB 🔴 +3.92 kB 🔴 +1.69 kB 🔴 +1.48 kB
assets/Media3DTop-CsfkD0G-.js (removed) 3.85 kB 🟢 -3.85 kB 🟢 -1.63 kB 🟢 -1.43 kB
assets/Media3DTop-t5_G9Id_.js (new) 3.85 kB 🔴 +3.85 kB 🔴 +1.62 kB 🔴 +1.43 kB
assets/GlobalToast-BFXxckT9.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.26 kB 🔴 +1.1 kB
assets/GlobalToast-DeAOVTMr.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.26 kB 🟢 -1.11 kB
assets/SubscribeToRun-CFbsx-fa.js (new) 2.13 kB 🔴 +2.13 kB 🔴 +982 B 🔴 +866 B
assets/SubscribeToRun-fUcqJhBf.js (removed) 2.13 kB 🟢 -2.13 kB 🟢 -983 B 🟢 -868 B
assets/MediaAudioTop-BJOV9dcp.js (new) 2.02 kB 🔴 +2.02 kB 🔴 +980 B 🔴 +832 B
assets/MediaAudioTop-CSMrIdXF.js (removed) 2.02 kB 🟢 -2.02 kB 🟢 -979 B 🟢 -832 B
assets/CloudRunButtonWrapper-CMWE5O7R.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -913 B 🟢 -808 B
assets/CloudRunButtonWrapper-CN74ILB6.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +910 B 🔴 +808 B
assets/graphHasMissingNodes-DwdwjLMX.js (removed) 1.83 kB 🟢 -1.83 kB 🟢 -862 B 🟢 -752 B
assets/graphHasMissingNodes-nOij7IuW.js (new) 1.83 kB 🔴 +1.83 kB 🔴 +862 B 🔴 +751 B
assets/cloudBadges-CybDxm0S.js (removed) 1.77 kB 🟢 -1.77 kB 🟢 -893 B 🟢 -779 B
assets/cloudBadges-DfArvqRy.js (new) 1.77 kB 🔴 +1.77 kB 🔴 +891 B 🔴 +768 B
assets/cloudSubscription-BCWlur_C.js (removed) 1.68 kB 🟢 -1.68 kB 🟢 -813 B 🟢 -701 B
assets/cloudSubscription-DDavC1Ac.js (new) 1.68 kB 🔴 +1.68 kB 🔴 +813 B 🔴 +701 B
assets/previousFullPath-DLzi4Rcr.js (removed) 1.53 kB 🟢 -1.53 kB 🟢 -694 B 🟢 -603 B
assets/previousFullPath-DTe5HpHo.js (new) 1.53 kB 🔴 +1.53 kB 🔴 +695 B 🔴 +601 B
assets/Load3D-BaMmSMhx.js (new) 1.34 kB 🔴 +1.34 kB 🔴 +615 B 🔴 +543 B
assets/Load3D-DMHAE2Fn.js (removed) 1.34 kB 🟢 -1.34 kB 🟢 -616 B 🟢 -546 B
assets/nightlyBadges-BGa8-IaC.js (removed) 1.29 kB 🟢 -1.29 kB 🟢 -659 B 🟢 -583 B
assets/nightlyBadges-C0NrDfiO.js (new) 1.29 kB 🔴 +1.29 kB 🔴 +658 B 🔴 +577 B
assets/Load3dViewerContent-BgoGDkpJ.js (new) 1.23 kB 🔴 +1.23 kB 🔴 +565 B 🔴 +499 B
assets/Load3dViewerContent-CMI58RqX.js (removed) 1.23 kB 🟢 -1.23 kB 🟢 -568 B 🟢 -500 B
assets/SubscriptionPanelContentWorkspace-CBkjBWsl.js (removed) 1.15 kB 🟢 -1.15 kB 🟢 -538 B 🟢 -469 B
assets/SubscriptionPanelContentWorkspace-DsSX2S41.js (new) 1.15 kB 🔴 +1.15 kB 🔴 +533 B 🔴 +465 B
assets/WidgetLegacy-cOeBDOe5.js (removed) 978 B 🟢 -978 B 🟢 -484 B 🟢 -426 B
assets/WidgetLegacy-DKLlgleE.js (new) 978 B 🔴 +978 B 🔴 +478 B 🔴 +426 B
assets/changeTracker-BhYmNYFv.js (removed) 952 B 🟢 -952 B 🟢 -472 B 🟢 -412 B
assets/changeTracker-CG4kL_7q.js (new) 952 B 🔴 +952 B 🔴 +467 B 🔴 +413 B

Status: 55 added / 55 removed / 79 unchanged

⚡ Performance Report

canvas-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 60.2 MB heap
canvas-mouse-sweep: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 56.4 MB heap
canvas-zoom-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 64.0 MB heap
dom-widget-clipping: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 47.0 MB heap
large-graph-idle: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 52.4 MB heap
large-graph-pan: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 66.4 MB heap
large-graph-zoom: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 61.9 MB heap
minimap-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 53.6 MB heap
subgraph-dom-widget-clipping: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 47.6 MB heap
subgraph-idle: · 60.0 avg FPS · 59.5 P5 FPS ✅ (target: ≥52) · 0ms TBT · 60.3 MB heap
subgraph-mouse-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 52.3 MB heap
viewport-pan-sweep: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 74.0 MB heap
vue-large-graph-idle: · 58.1 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 158.0 MB heap
vue-large-graph-pan: · 56.3 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 1ms TBT · 164.0 MB heap
workflow-execution: · 60.0 avg FPS · 59.9 P5 FPS ✅ (target: ≥52) · 0ms TBT · 46.9 MB heap

⚠️ 9 regressions detected

Metric Baseline PR (median) Δ Sig
canvas-mouse-sweep: task duration 923ms 1051ms +14% ⚠️ z=3.2
large-graph-idle: task duration 527ms 700ms +33% ⚠️ z=2.9
large-graph-idle: script duration 98ms 126ms +29% ⚠️ z=2.3
large-graph-pan: task duration 1053ms 1215ms +15% ⚠️ z=3.1
minimap-idle: task duration 504ms 678ms +34% ⚠️ z=3.2
minimap-idle: script duration 85ms 121ms +42% ⚠️ z=2.3
subgraph-idle: task duration 329ms 433ms +32% ⚠️ z=2.0
subgraph-mouse-sweep: style recalc duration 43ms 55ms +29% ⚠️ z=3.7
subgraph-mouse-sweep: task duration 876ms 1005ms +15% ⚠️ z=3.5
All metrics
Metric Baseline PR (median) Δ Sig
canvas-idle: avg frame time 17ms 17ms +0% z=-0.1
canvas-idle: p95 frame time 17ms 17ms +0%
canvas-idle: layout duration 0ms 0ms +0%
canvas-idle: style recalc duration 8ms 12ms +42% z=1.0
canvas-idle: layout count 0 0 +0%
canvas-idle: style recalc count 10 12 +20% z=1.5
canvas-idle: task duration 340ms 447ms +31% z=1.7
canvas-idle: script duration 22ms 29ms +34% z=1.7
canvas-idle: TBT 0ms 0ms +0%
canvas-idle: heap used 60.2 MB 60.2 MB +0%
canvas-idle: DOM nodes 19 23 +21% z=0.3
canvas-idle: event listeners 6 6 +0% z=-1.2
canvas-mouse-sweep: avg frame time 17ms 17ms +0% z=-0.4
canvas-mouse-sweep: p95 frame time 17ms 17ms +1%
canvas-mouse-sweep: layout duration 3ms 4ms +11% z=-0.3
canvas-mouse-sweep: style recalc duration 40ms 48ms +20% z=1.5
canvas-mouse-sweep: layout count 12 12 +0%
canvas-mouse-sweep: style recalc count 80 82 +3% z=1.4
canvas-mouse-sweep: task duration 923ms 1051ms +14% ⚠️ z=3.2
canvas-mouse-sweep: script duration 133ms 148ms +11% z=1.9
canvas-mouse-sweep: TBT 0ms 0ms +0%
canvas-mouse-sweep: heap used 57.4 MB 56.4 MB -2%
canvas-mouse-sweep: DOM nodes 65 65 +0% z=1.0
canvas-mouse-sweep: event listeners 6 6 +0% z=-0.6
canvas-zoom-sweep: avg frame time 17ms 17ms +0% z=0.5
canvas-zoom-sweep: p95 frame time 17ms 17ms +0%
canvas-zoom-sweep: layout duration 1ms 1ms +32% z=0.9
canvas-zoom-sweep: style recalc duration 16ms 20ms +20% z=0.4
canvas-zoom-sweep: layout count 6 6 +0%
canvas-zoom-sweep: style recalc count 31 32 +3% z=1.6
canvas-zoom-sweep: task duration 286ms 364ms +27% z=1.6
canvas-zoom-sweep: script duration 23ms 31ms +31% z=1.2
canvas-zoom-sweep: TBT 0ms 0ms +0%
canvas-zoom-sweep: heap used 64.0 MB 64.0 MB -0%
canvas-zoom-sweep: DOM nodes 79 79 +0% z=-0.3
canvas-zoom-sweep: event listeners 19 19 +0% z=-0.9
dom-widget-clipping: avg frame time 17ms 17ms -0% z=-0.6
dom-widget-clipping: p95 frame time 17ms 17ms +1%
dom-widget-clipping: layout duration 0ms 0ms +0%
dom-widget-clipping: style recalc duration 10ms 10ms +5% z=0.3
dom-widget-clipping: layout count 0 0 +0%
dom-widget-clipping: style recalc count 13 12 -8% z=-2.2
dom-widget-clipping: task duration 336ms 384ms +14% z=1.2
dom-widget-clipping: script duration 63ms 73ms +16% z=1.6
dom-widget-clipping: TBT 0ms 0ms +0%
dom-widget-clipping: heap used 47.0 MB 47.0 MB +0%
dom-widget-clipping: DOM nodes 22 20 -9% z=-1.5
dom-widget-clipping: event listeners 2 2 +0% variance too high
large-graph-idle: avg frame time 17ms 17ms +0% z=-0.2
large-graph-idle: p95 frame time 17ms 17ms -1%
large-graph-idle: layout duration 0ms 0ms +0%
large-graph-idle: style recalc duration 10ms 10ms +5% z=-1.7
large-graph-idle: layout count 0 0 +0%
large-graph-idle: style recalc count 11 11 +0% z=-1.9
large-graph-idle: task duration 527ms 700ms +33% ⚠️ z=2.9
large-graph-idle: script duration 98ms 126ms +29% ⚠️ z=2.3
large-graph-idle: TBT 0ms 0ms +0%
large-graph-idle: heap used 53.1 MB 52.4 MB -1%
large-graph-idle: DOM nodes -257 -258 +0% z=-312.8
large-graph-idle: event listeners -125 -127 +2% z=-25.1
large-graph-pan: avg frame time 17ms 17ms +0% z=0.3
large-graph-pan: p95 frame time 17ms 17ms -0%
large-graph-pan: layout duration 0ms 0ms +0%
large-graph-pan: style recalc duration 16ms 17ms +6% z=-0.6
large-graph-pan: layout count 0 0 +0%
large-graph-pan: style recalc count 70 68 -3% z=-2.4
large-graph-pan: task duration 1053ms 1215ms +15% ⚠️ z=3.1
large-graph-pan: script duration 395ms 429ms +9% z=1.0
large-graph-pan: TBT 0ms 0ms +0%
large-graph-pan: heap used 67.3 MB 66.4 MB -1%
large-graph-pan: DOM nodes -260 -263 +1% z=-170.9
large-graph-pan: event listeners -125 -127 +2% z=-159.3
large-graph-zoom: avg frame time 17ms 17ms -0%
large-graph-zoom: p95 frame time 17ms 17ms +1%
large-graph-zoom: layout duration 7ms 8ms +20%
large-graph-zoom: style recalc duration 16ms 18ms +11%
large-graph-zoom: layout count 60 60 +0%
large-graph-zoom: style recalc count 66 65 -2%
large-graph-zoom: task duration 1269ms 1495ms +18%
large-graph-zoom: script duration 474ms 560ms +18%
large-graph-zoom: TBT 0ms 0ms +0%
large-graph-zoom: heap used 57.9 MB 61.9 MB +7%
large-graph-zoom: DOM nodes -264 -267 +1%
large-graph-zoom: event listeners -125 -123 -2%
minimap-idle: avg frame time 17ms 17ms -0% z=-0.9
minimap-idle: p95 frame time 17ms 17ms -0%
minimap-idle: layout duration 0ms 0ms +0%
minimap-idle: style recalc duration 9ms 9ms -5% z=-0.9
minimap-idle: layout count 0 0 +0%
minimap-idle: style recalc count 10 9 -10% z=-0.8
minimap-idle: task duration 504ms 678ms +34% ⚠️ z=3.2
minimap-idle: script duration 85ms 121ms +42% ⚠️ z=2.3
minimap-idle: TBT 0ms 0ms +0%
minimap-idle: heap used 53.8 MB 53.6 MB -0%
minimap-idle: DOM nodes -260 -262 +1% z=-205.6
minimap-idle: event listeners -127 -127 +0% z=-199.3
subgraph-dom-widget-clipping: avg frame time 17ms 17ms +0% z=0.1
subgraph-dom-widget-clipping: p95 frame time 17ms 17ms +1%
subgraph-dom-widget-clipping: layout duration 0ms 0ms +0%
subgraph-dom-widget-clipping: style recalc duration 12ms 13ms +10% z=0.2
subgraph-dom-widget-clipping: layout count 0 0 +0%
subgraph-dom-widget-clipping: style recalc count 49 47 -4% z=-1.6
subgraph-dom-widget-clipping: task duration 343ms 395ms +15% z=0.9
subgraph-dom-widget-clipping: script duration 121ms 133ms +10% z=0.8
subgraph-dom-widget-clipping: TBT 0ms 0ms +0%
subgraph-dom-widget-clipping: heap used 46.9 MB 47.6 MB +1%
subgraph-dom-widget-clipping: DOM nodes 23 20 -13% z=-1.9
subgraph-dom-widget-clipping: event listeners 8 8 +0% z=-1.4
subgraph-idle: avg frame time 17ms 17ms +0% z=0.4
subgraph-idle: p95 frame time 17ms 17ms +0%
subgraph-idle: layout duration 0ms 0ms +0%
subgraph-idle: style recalc duration 9ms 11ms +16% z=0.4
subgraph-idle: layout count 0 0 +0%
subgraph-idle: style recalc count 11 10 -9% z=-1.4
subgraph-idle: task duration 329ms 433ms +32% ⚠️ z=2.0
subgraph-idle: script duration 18ms 25ms +42% z=1.9
subgraph-idle: TBT 0ms 0ms +0%
subgraph-idle: heap used 60.1 MB 60.3 MB +0%
subgraph-idle: DOM nodes 22 20 -9% z=-1.2
subgraph-idle: event listeners 6 6 +0% variance too high
subgraph-mouse-sweep: avg frame time 17ms 17ms +0% z=0.4
subgraph-mouse-sweep: p95 frame time 17ms 17ms +0%
subgraph-mouse-sweep: layout duration 4ms 5ms +13% z=0.3
subgraph-mouse-sweep: style recalc duration 43ms 55ms +29% ⚠️ z=3.7
subgraph-mouse-sweep: layout count 16 16 +0%
subgraph-mouse-sweep: style recalc count 83 85 +2% z=2.5
subgraph-mouse-sweep: task duration 876ms 1005ms +15% ⚠️ z=3.5
subgraph-mouse-sweep: script duration 97ms 112ms +16% z=1.8
subgraph-mouse-sweep: TBT 0ms 0ms +0%
subgraph-mouse-sweep: heap used 52.1 MB 52.3 MB +0%
subgraph-mouse-sweep: DOM nodes 72 73 +1% z=2.7
subgraph-mouse-sweep: event listeners 6 6 +0% variance too high
viewport-pan-sweep: avg frame time 17ms 17ms +0%
viewport-pan-sweep: p95 frame time 17ms 17ms +0%
viewport-pan-sweep: layout duration 0ms 0ms +0%
viewport-pan-sweep: style recalc duration 42ms 48ms +15%
viewport-pan-sweep: layout count 0 0 +0%
viewport-pan-sweep: style recalc count 250 251 +0%
viewport-pan-sweep: task duration 3523ms 4287ms +22%
viewport-pan-sweep: script duration 1226ms 1445ms +18%
viewport-pan-sweep: TBT 0ms 0ms +0%
viewport-pan-sweep: heap used 72.9 MB 74.0 MB +1%
viewport-pan-sweep: DOM nodes -257 -259 +1%
viewport-pan-sweep: event listeners -111 -111 +0%
vue-large-graph-idle: avg frame time 17ms 17ms +0%
vue-large-graph-idle: p95 frame time 17ms 17ms +0%
vue-large-graph-idle: layout duration 0ms 0ms +0%
vue-large-graph-idle: style recalc duration 0ms 0ms +0%
vue-large-graph-idle: layout count 0 0 +0%
vue-large-graph-idle: style recalc count 0 0 +0%
vue-large-graph-idle: task duration 11546ms 13677ms +18%
vue-large-graph-idle: script duration 572ms 658ms +15%
vue-large-graph-idle: TBT 0ms 0ms +0%
vue-large-graph-idle: heap used 157.8 MB 158.0 MB +0%
vue-large-graph-idle: DOM nodes -8331 -8331 +0%
vue-large-graph-idle: event listeners -16464 -16460 -0%
vue-large-graph-pan: avg frame time 17ms 18ms +3%
vue-large-graph-pan: p95 frame time 17ms 17ms -1%
vue-large-graph-pan: layout duration 0ms 0ms +0%
vue-large-graph-pan: style recalc duration 13ms 17ms +36%
vue-large-graph-pan: layout count 0 0 +0%
vue-large-graph-pan: style recalc count 67 78 +16%
vue-large-graph-pan: task duration 13782ms 15530ms +13%
vue-large-graph-pan: script duration 875ms 989ms +13%
vue-large-graph-pan: TBT 0ms 1ms
vue-large-graph-pan: heap used 141.1 MB 164.0 MB +16%
vue-large-graph-pan: DOM nodes -8331 -8331 +0%
vue-large-graph-pan: event listeners -16486 -16456 -0%
workflow-execution: avg frame time 17ms 17ms +0% z=0.6
workflow-execution: p95 frame time 17ms 17ms +0%
workflow-execution: layout duration 1ms 1ms +15% z=-0.9
workflow-execution: style recalc duration 24ms 25ms +4% z=0.5
workflow-execution: layout count 5 5 +0% z=0.1
workflow-execution: style recalc count 19 18 -5% z=0.1
workflow-execution: task duration 120ms 130ms +9% z=0.7
workflow-execution: script duration 29ms 31ms +7% z=0.6
workflow-execution: TBT 0ms 0ms +0%
workflow-execution: heap used 47.4 MB 46.9 MB -1%
workflow-execution: DOM nodes 158 156 -1% z=-0.7
workflow-execution: event listeners 71 71 +0% z=4.4
Historical variance (last 15 runs)
Metric μ σ CV
canvas-idle: avg frame time 17ms 0ms 0.0%
canvas-idle: layout duration 0ms 0ms 0.0%
canvas-idle: style recalc duration 11ms 1ms 8.2%
canvas-idle: layout count 0 0 0.0%
canvas-idle: style recalc count 11 1 5.0%
canvas-idle: task duration 395ms 31ms 7.9%
canvas-idle: script duration 25ms 2ms 8.8%
canvas-idle: TBT 0ms 0ms 0.0%
canvas-idle: DOM nodes 23 1 5.6%
canvas-idle: event listeners 12 5 40.9%
canvas-mouse-sweep: avg frame time 17ms 0ms 0.0%
canvas-mouse-sweep: layout duration 4ms 0ms 5.4%
canvas-mouse-sweep: style recalc duration 43ms 3ms 7.4%
canvas-mouse-sweep: layout count 12 0 0.0%
canvas-mouse-sweep: style recalc count 79 2 3.0%
canvas-mouse-sweep: task duration 865ms 58ms 6.7%
canvas-mouse-sweep: script duration 136ms 6ms 4.8%
canvas-mouse-sweep: TBT 0ms 0ms 0.0%
canvas-mouse-sweep: DOM nodes 62 3 4.2%
canvas-mouse-sweep: event listeners 8 4 49.4%
canvas-zoom-sweep: avg frame time 17ms 0ms 0.0%
canvas-zoom-sweep: layout duration 1ms 0ms 7.0%
canvas-zoom-sweep: style recalc duration 19ms 2ms 8.0%
canvas-zoom-sweep: layout count 6 0 0.0%
canvas-zoom-sweep: style recalc count 31 0 1.5%
canvas-zoom-sweep: task duration 327ms 23ms 7.1%
canvas-zoom-sweep: script duration 27ms 3ms 11.1%
canvas-zoom-sweep: TBT 0ms 0ms 0.0%
canvas-zoom-sweep: DOM nodes 79 1 1.0%
canvas-zoom-sweep: event listeners 24 5 21.8%
dom-widget-clipping: avg frame time 17ms 0ms 0.0%
dom-widget-clipping: layout duration 0ms 0ms 0.0%
dom-widget-clipping: style recalc duration 10ms 1ms 8.0%
dom-widget-clipping: layout count 0 0 0.0%
dom-widget-clipping: style recalc count 13 0 3.8%
dom-widget-clipping: task duration 365ms 16ms 4.5%
dom-widget-clipping: script duration 68ms 3ms 4.8%
dom-widget-clipping: TBT 0ms 0ms 0.0%
dom-widget-clipping: DOM nodes 22 1 6.4%
dom-widget-clipping: event listeners 8 6 81.2%
large-graph-idle: avg frame time 17ms 0ms 0.0%
large-graph-idle: layout duration 0ms 0ms 0.0%
large-graph-idle: style recalc duration 12ms 1ms 8.6%
large-graph-idle: layout count 0 0 0.0%
large-graph-idle: style recalc count 12 0 2.7%
large-graph-idle: task duration 542ms 54ms 10.0%
large-graph-idle: script duration 102ms 11ms 10.3%
large-graph-idle: TBT 0ms 0ms 0.0%
large-graph-idle: DOM nodes 25 1 3.7%
large-graph-idle: event listeners 26 6 23.2%
large-graph-pan: avg frame time 17ms 0ms 0.0%
large-graph-pan: layout duration 0ms 0ms 0.0%
large-graph-pan: style recalc duration 17ms 1ms 4.6%
large-graph-pan: layout count 0 0 0.0%
large-graph-pan: style recalc count 70 1 0.9%
large-graph-pan: task duration 1082ms 43ms 4.0%
large-graph-pan: script duration 408ms 20ms 4.8%
large-graph-pan: TBT 0ms 0ms 0.0%
large-graph-pan: DOM nodes 19 2 8.7%
large-graph-pan: event listeners 5 1 16.8%
minimap-idle: avg frame time 17ms 0ms 0.0%
minimap-idle: layout duration 0ms 0ms 0.0%
minimap-idle: style recalc duration 10ms 1ms 8.6%
minimap-idle: layout count 0 0 0.0%
minimap-idle: style recalc count 10 1 7.1%
minimap-idle: task duration 527ms 47ms 9.0%
minimap-idle: script duration 98ms 10ms 10.1%
minimap-idle: TBT 0ms 0ms 0.0%
minimap-idle: DOM nodes 19 1 7.1%
minimap-idle: event listeners 5 1 14.4%
subgraph-dom-widget-clipping: avg frame time 17ms 0ms 0.0%
subgraph-dom-widget-clipping: layout duration 0ms 0ms 0.0%
subgraph-dom-widget-clipping: style recalc duration 13ms 1ms 7.4%
subgraph-dom-widget-clipping: layout count 0 0 0.0%
subgraph-dom-widget-clipping: style recalc count 48 1 1.2%
subgraph-dom-widget-clipping: task duration 378ms 18ms 4.9%
subgraph-dom-widget-clipping: script duration 128ms 6ms 4.9%
subgraph-dom-widget-clipping: TBT 0ms 0ms 0.0%
subgraph-dom-widget-clipping: DOM nodes 22 1 5.0%
subgraph-dom-widget-clipping: event listeners 16 6 36.0%
subgraph-idle: avg frame time 17ms 0ms 0.0%
subgraph-idle: layout duration 0ms 0ms 0.0%
subgraph-idle: style recalc duration 10ms 1ms 7.5%
subgraph-idle: layout count 0 0 0.0%
subgraph-idle: style recalc count 11 1 6.0%
subgraph-idle: task duration 370ms 31ms 8.5%
subgraph-idle: script duration 20ms 3ms 13.2%
subgraph-idle: TBT 0ms 0ms 0.0%
subgraph-idle: DOM nodes 22 1 6.9%
subgraph-idle: event listeners 10 7 64.5%
subgraph-mouse-sweep: avg frame time 17ms 0ms 0.0%
subgraph-mouse-sweep: layout duration 5ms 0ms 6.8%
subgraph-mouse-sweep: style recalc duration 42ms 3ms 7.8%
subgraph-mouse-sweep: layout count 16 0 0.0%
subgraph-mouse-sweep: style recalc count 80 2 2.4%
subgraph-mouse-sweep: task duration 766ms 69ms 9.0%
subgraph-mouse-sweep: script duration 101ms 7ms 6.5%
subgraph-mouse-sweep: TBT 0ms 0ms 0.0%
subgraph-mouse-sweep: DOM nodes 67 2 3.3%
subgraph-mouse-sweep: event listeners 8 4 52.6%
workflow-execution: avg frame time 17ms 0ms 0.0%
workflow-execution: layout duration 2ms 0ms 9.4%
workflow-execution: style recalc duration 24ms 2ms 9.1%
workflow-execution: layout count 5 1 11.0%
workflow-execution: style recalc count 18 2 11.5%
workflow-execution: task duration 123ms 11ms 8.8%
workflow-execution: script duration 29ms 3ms 10.2%
workflow-execution: TBT 0ms 0ms 0.0%
workflow-execution: DOM nodes 161 7 4.4%
workflow-execution: event listeners 52 4 8.4%
Trend (last 15 commits on main)
Metric Trend Dir Latest
canvas-idle: avg frame time ▆▃▆▁▆▃▆█▆▆▄▃▃▄▃ ➡️ 17ms
canvas-idle: p95 frame time ➡️ NaNms
canvas-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: style recalc duration ▇▇▆▆▃█▄▃▄▃▇▄▁▆▇ ➡️ 11ms
canvas-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
canvas-idle: style recalc count █▃▅▂▅▆▃▁▂▁▂▅▆▅▆ ➡️ 12
canvas-idle: task duration ▃▃▃▆▂▃▃▅▆▂█▃▁▃▃ ➡️ 391ms
canvas-idle: script duration ▄▃▅▇▂▅▃▆▇▅█▄▁▅▆ ➡️ 27ms
canvas-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-idle: heap used ➡️ NaN MB
canvas-idle: DOM nodes █▇▆▅▃▇▃▁▂▂▅▆▆▆▇ ➡️ 24
canvas-idle: event listeners ▅█▅▄▁▅▁▁▁▄▅▅▁▅▄ 📉 11
canvas-mouse-sweep: avg frame time ▆█▆▃▁▃▁▆▆▁▃▆▆▃▃ ➡️ 17ms
canvas-mouse-sweep: p95 frame time ➡️ NaNms
canvas-mouse-sweep: layout duration ▁▃▂▄▁▂▁▃▆▂█▇▆▄▃ ➡️ 4ms
canvas-mouse-sweep: style recalc duration ▄▄▂▄▁▂▃▃▅▄█▆▂▄▄ ➡️ 43ms
canvas-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 12
canvas-mouse-sweep: style recalc count █▅▄▃▂▂▁▄▄▅▆▅▂▇▄ ➡️ 79
canvas-mouse-sweep: task duration █▆▄▂▂▃▂▄▄▅█▆▁▆▄ ➡️ 868ms
canvas-mouse-sweep: script duration ▄▅▄▆▄▆▆▆▅▅█▆▁▅▆ ➡️ 139ms
canvas-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-mouse-sweep: heap used ➡️ NaN MB
canvas-mouse-sweep: DOM nodes █▅▃▃▁▂▂▃▂▄▆▅▃▅▅ ➡️ 64
canvas-mouse-sweep: event listeners █▁▁▁▁▁▇▁▁▁██▇▁█ 📈 13
canvas-zoom-sweep: avg frame time ▅▅█▄▅▁▁▁▅▁▁▅▄▅▁ ➡️ 17ms
canvas-zoom-sweep: p95 frame time ➡️ NaNms
canvas-zoom-sweep: layout duration ▆▅▅▄▁▁█▅▃▅▇▆▁▂▆ ➡️ 1ms
canvas-zoom-sweep: style recalc duration ▆▅▄▆▅▃█▆▇▅▇▄▁▃▅ ➡️ 20ms
canvas-zoom-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 6
canvas-zoom-sweep: style recalc count ▁▁▃▄▆▃▆█▄▄▆▁▆▁▆ ➡️ 32
canvas-zoom-sweep: task duration ▄▂▁▇▂▂▄▅▆▃█▄▁▁▅ ➡️ 338ms
canvas-zoom-sweep: script duration ▃▃▂▇▂▂▅▇▆▅█▄▁▂▆ ➡️ 30ms
canvas-zoom-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
canvas-zoom-sweep: heap used ➡️ NaN MB
canvas-zoom-sweep: DOM nodes ▄▃▁▅█▁▃▆▄▅▅▃▃▄▃ ➡️ 79
canvas-zoom-sweep: event listeners ▁▁▂▅█▂▁▅▁▅▅▄▁▅▁ ➡️ 19
dom-widget-clipping: avg frame time ▂▄▅▅▂▄█▇▅▇▇▅▅▁▇ ➡️ 17ms
dom-widget-clipping: p95 frame time ➡️ NaNms
dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: style recalc duration ▆▆▂▆▄▃██▄▁▆▇▆▃▅ ➡️ 10ms
dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
dom-widget-clipping: style recalc count ▇█▅█▅▄█▇▇▁▇▄▇▂▅ ➡️ 13
dom-widget-clipping: task duration ▃▃▁▅▄▃▅▆▅▂▇█▁▅▅ ➡️ 371ms
dom-widget-clipping: script duration ▅▄▄▆▆▅▇▇▆▃█▇▁▇▇ ➡️ 71ms
dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
dom-widget-clipping: heap used ➡️ NaN MB
dom-widget-clipping: DOM nodes ▇▇▄▇▅▄█▇▅▁▅▄▇▃▄ ➡️ 21
dom-widget-clipping: event listeners ▅▅▅▅▁▅██▁▁▁▁█▁▁ 📉 2
large-graph-idle: avg frame time ▅▅▅▅▅▂▁▂▄▅▄▂▂▅█ ➡️ 17ms
large-graph-idle: p95 frame time ➡️ NaNms
large-graph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: style recalc duration ▅▅▅▆▄▅▃▄▅▅▆█▁▄▆ ➡️ 13ms
large-graph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-idle: style recalc count █▆█▃▃▁▃▆▃▆▆▃▆██ ➡️ 12
large-graph-idle: task duration ▂▃▂▆▂▃▃▇▅▃██▁▂▅ ➡️ 569ms
large-graph-idle: script duration ▄▅▄▆▄▅▅▇▆▅█▆▁▃▆ ➡️ 110ms
large-graph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-idle: heap used ➡️ NaN MB
large-graph-idle: DOM nodes ▆█▅▂▅▃▁▂▃▅▅▆▂▆▅ ➡️ 25
large-graph-idle: event listeners ███▇██▄▁▄▇▇█▂█▇ ➡️ 29
large-graph-pan: avg frame time ▆▃▃▆█▃▁█▆▆▆▆█▁▆ ➡️ 17ms
large-graph-pan: p95 frame time ➡️ NaNms
large-graph-pan: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: style recalc duration ▃▂▄▄▁▅▂▂▁▄▄█▃▁▂ ➡️ 17ms
large-graph-pan: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
large-graph-pan: style recalc count ▆▃█▂▃▂▂▂▁▇▅▃█▆▃ ➡️ 69
large-graph-pan: task duration ▄▃▄▆▄▄▄▆▄▄█▆▁▂▅ ➡️ 1100ms
large-graph-pan: script duration ▅▄▅▆▆▅▄▆▄▅█▄▁▄▅ ➡️ 413ms
large-graph-pan: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
large-graph-pan: heap used ➡️ NaN MB
large-graph-pan: DOM nodes ▅▃▆▂▄▁▃▁▁▅▁▂█▅▂ ➡️ 18
large-graph-pan: event listeners █▆█▁▁▆▁▁▃▆▁▃██▃ ➡️ 5
minimap-idle: avg frame time ▃▆▆▃█▁█▆▆▃▃▆█▆█ ➡️ 17ms
minimap-idle: p95 frame time ➡️ NaNms
minimap-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: style recalc duration ▄█▁█▅▅█▅▅▃▅▁▁▄▆ ➡️ 10ms
minimap-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
minimap-idle: style recalc count ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 9
minimap-idle: task duration ▃▄▁▅▁▃▄▅▇▃█▅▁▁▅ ➡️ 547ms
minimap-idle: script duration ▄▆▃▇▃▅▆▆▇▅█▅▁▃▆ ➡️ 106ms
minimap-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
minimap-idle: heap used ➡️ NaN MB
minimap-idle: DOM nodes ▃▅▂▄█▃▆▁▂▅▂▁▅▆▃ ➡️ 19
minimap-idle: event listeners ▃▃▆▁▁▁▃▁▁▆▁▃█▆▁ ➡️ 4
subgraph-dom-widget-clipping: avg frame time ▅▄▄▄▄▄█▄▄▄▃▁▆▃▃ ➡️ 17ms
subgraph-dom-widget-clipping: p95 frame time ➡️ NaNms
subgraph-dom-widget-clipping: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: style recalc duration ▂▄▃▅▅▃▂▅▇▃▄█▁▄▆ ➡️ 14ms
subgraph-dom-widget-clipping: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-dom-widget-clipping: style recalc count ▇█▆▃▆▃▁▆█▇▃▆▇█▅ ➡️ 48
subgraph-dom-widget-clipping: task duration ▂▃▃▆▅▅▂▅█▂▆█▁▂▇ ➡️ 398ms
subgraph-dom-widget-clipping: script duration ▃▃▃▄▅▅▂▄█▂▅▇▁▂▅ ➡️ 131ms
subgraph-dom-widget-clipping: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-dom-widget-clipping: heap used ➡️ NaN MB
subgraph-dom-widget-clipping: DOM nodes ▅▇▅▂▅▂▁▅▅▅▁▇▅█▄ ➡️ 22
subgraph-dom-widget-clipping: event listeners ▅▅▅▂▅▁▅██▁▁█▅█▅ 📈 16
subgraph-idle: avg frame time ▆▆█▁▆▃▆▆▆▃▆▁▃▆█ ➡️ 17ms
subgraph-idle: p95 frame time ➡️ NaNms
subgraph-idle: layout duration ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: style recalc duration ▁▇▃▆▂▄▂▃▃▆▆▄▃▇█ ➡️ 12ms
subgraph-idle: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0
subgraph-idle: style recalc count ▃▆▃▃▂▅▁▂▁▆▃▃██▇ ➡️ 12
subgraph-idle: task duration ▁▃▁▇▁▁▃▆▅▂█▅▁▁▄ ➡️ 378ms
subgraph-idle: script duration ▁▃▂▇▁▂▃▇▆▂█▅▂▁▅ ➡️ 22ms
subgraph-idle: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-idle: heap used ➡️ NaN MB
subgraph-idle: DOM nodes ▃▅▃▂▁▄▁▂▁▅▃▂▇█▇ ➡️ 24
subgraph-idle: event listeners ▁▅▁▁▁▁▁▁▁▅▄▁███ 📈 21
subgraph-mouse-sweep: avg frame time ▅▄▁▃▃▄▆▄▆▃▃█▁▃▃ ➡️ 17ms
subgraph-mouse-sweep: p95 frame time ➡️ NaNms
subgraph-mouse-sweep: layout duration ▁▄▄▄▃▃▅▅▅▂█▇▂▃▆ ➡️ 5ms
subgraph-mouse-sweep: style recalc duration ▃▂▄▅▂▃▄▅█▃█▆▁▂▅ ➡️ 43ms
subgraph-mouse-sweep: layout count ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 16
subgraph-mouse-sweep: style recalc count ▅▂▅▅▁▄▃▅█▅▆▄▂▄▅ ➡️ 81
subgraph-mouse-sweep: task duration ▃▂▄▅▂▄▄▅▇▄█▆▁▃▅ ➡️ 785ms
subgraph-mouse-sweep: script duration ▄▅▄▇▅▅▆▇▆▅██▁▄▆ ➡️ 105ms
subgraph-mouse-sweep: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
subgraph-mouse-sweep: heap used ➡️ NaN MB
subgraph-mouse-sweep: DOM nodes ▅▁▄▅▁▄▃▃█▅▅▄▂▅▃ ➡️ 66
subgraph-mouse-sweep: event listeners ▇▁▂▇▁▂▂▂█▇▂▂▇▇▂ 📈 5
workflow-execution: avg frame time ▆▆▆▄▆▆▃▄▁▄█▆▅▄▆ ➡️ 17ms
workflow-execution: p95 frame time ➡️ NaNms
workflow-execution: layout duration ▁▆▁▃▂▄▃▂▃▃▅█▄▂▅ ➡️ 2ms
workflow-execution: style recalc duration ▃▇▅▇▁▅▆▇█▁██▂▄▆ ➡️ 25ms
workflow-execution: layout count ▁█▂▃▂▃▃▁▃▃▄▃▂▃▂ ➡️ 5
workflow-execution: style recalc count ▃█▅▇▁▄▅▆▅▅▅▅▄▄▂ ➡️ 15
workflow-execution: task duration ▂▅▄▅▁▄▆▆▆▁▇█▁▃▃ ➡️ 120ms
workflow-execution: script duration ▄▃▄▄▃▅▄▅▆▂▇█▁▃▄ ➡️ 29ms
workflow-execution: TBT ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ➡️ 0ms
workflow-execution: heap used ➡️ NaN MB
workflow-execution: DOM nodes ▂█▃▆▁▄▃▅▃█▃▃▄▃▁ ➡️ 152
workflow-execution: event listeners ▅███▁▅███▁██▅█▅ ➡️ 49
Raw data
{
  "timestamp": "2026-03-30T01:09:38.491Z",
  "gitSha": "61ca954c27eb23ac252fb2f351091dff284a93af",
  "branch": "playwright-test-agents-system",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2022.8989999999953,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 11.518,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 466.29,
      "heapDeltaBytes": 20351692,
      "heapUsedBytes": 62735616,
      "domNodes": 23,
      "jsHeapTotalBytes": 23068672,
      "scriptDurationMs": 30.779999999999994,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-idle",
      "durationMs": 2028.5220000000095,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 12.657000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 446.59299999999996,
      "heapDeltaBytes": 20187704,
      "heapUsedBytes": 63199688,
      "domNodes": 23,
      "jsHeapTotalBytes": 22544384,
      "scriptDurationMs": 27.872,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-idle",
      "durationMs": 2066.2249999999176,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 11.697,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 445.95700000000005,
      "heapDeltaBytes": 20332456,
      "heapUsedBytes": 63095852,
      "domNodes": 20,
      "jsHeapTotalBytes": 23330816,
      "scriptDurationMs": 29.010999999999996,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 2049.6880000000033,
      "styleRecalcs": 81,
      "styleRecalcDurationMs": 52.994,
      "layouts": 12,
      "layoutDurationMs": 3.852,
      "taskDurationMs": 1085.653,
      "heapDeltaBytes": 16826468,
      "heapUsedBytes": 61036140,
      "domNodes": 66,
      "jsHeapTotalBytes": 23330816,
      "scriptDurationMs": 153.81,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 2054.9819999999954,
      "styleRecalcs": 82,
      "styleRecalcDurationMs": 47.547000000000004,
      "layouts": 12,
      "layoutDurationMs": 3.5589999999999997,
      "taskDurationMs": 1050.5040000000001,
      "heapDeltaBytes": 16293332,
      "heapUsedBytes": 59100632,
      "domNodes": 65,
      "jsHeapTotalBytes": 23592960,
      "scriptDurationMs": 147.602,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 2044.8949999999968,
      "styleRecalcs": 83,
      "styleRecalcDurationMs": 46.781000000000006,
      "layouts": 12,
      "layoutDurationMs": 3.438,
      "taskDurationMs": 1046.6339999999998,
      "heapDeltaBytes": 7348904,
      "heapUsedBytes": 58726384,
      "domNodes": 65,
      "jsHeapTotalBytes": 26214400,
      "scriptDurationMs": 145.614,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1767.4240000000054,
      "styleRecalcs": 31,
      "styleRecalcDurationMs": 23.489,
      "layouts": 6,
      "layoutDurationMs": 0.6839999999999999,
      "taskDurationMs": 396.879,
      "heapDeltaBytes": 15684516,
      "heapUsedBytes": 67102720,
      "domNodes": 78,
      "jsHeapTotalBytes": 23068672,
      "scriptDurationMs": 34.379,
      "eventListeners": 21,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1739.3900000000144,
      "styleRecalcs": 34,
      "styleRecalcDurationMs": 19.189000000000004,
      "layouts": 6,
      "layoutDurationMs": 0.627,
      "taskDurationMs": 363.63900000000007,
      "heapDeltaBytes": 15106204,
      "heapUsedBytes": 66741620,
      "domNodes": 79,
      "jsHeapTotalBytes": 23068672,
      "scriptDurationMs": 26.018,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "canvas-zoom-sweep",
      "durationMs": 1739.6059999999807,
      "styleRecalcs": 32,
      "styleRecalcDurationMs": 19.673999999999996,
      "layouts": 6,
      "layoutDurationMs": 0.699,
      "taskDurationMs": 350.76700000000005,
      "heapDeltaBytes": 24703352,
      "heapUsedBytes": 67127524,
      "domNodes": 79,
      "jsHeapTotalBytes": 19922944,
      "scriptDurationMs": 30.62600000000001,
      "eventListeners": 19,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 648.2129999999984,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 10.077999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 409.293,
      "heapDeltaBytes": 6538572,
      "heapUsedBytes": 49291220,
      "domNodes": 20,
      "jsHeapTotalBytes": 13369344,
      "scriptDurationMs": 81.816,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.663333333333338,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 590.9679999999753,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 9.853999999999997,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 383.64300000000003,
      "heapDeltaBytes": 6347936,
      "heapUsedBytes": 49304896,
      "domNodes": 19,
      "jsHeapTotalBytes": 12845056,
      "scriptDurationMs": 66.79,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.663333333333338,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 582.5640000000476,
      "styleRecalcs": 13,
      "styleRecalcDurationMs": 10.563999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 378.679,
      "heapDeltaBytes": 6201924,
      "heapUsedBytes": 48954068,
      "domNodes": 22,
      "jsHeapTotalBytes": 13107200,
      "scriptDurationMs": 72.989,
      "eventListeners": 2,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999727
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2014.4170000000088,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.413000000000002,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 699.567,
      "heapDeltaBytes": 3441016,
      "heapUsedBytes": 54635812,
      "domNodes": -257,
      "jsHeapTotalBytes": 16707584,
      "scriptDurationMs": 126.45200000000001,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2076.8729999999778,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 11.612,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 719.548,
      "heapDeltaBytes": -21378324,
      "heapUsedBytes": 54989588,
      "domNodes": -258,
      "jsHeapTotalBytes": 17612800,
      "scriptDurationMs": 132.956,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-idle",
      "durationMs": 2044.9929999999767,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 9.961,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 609.554,
      "heapDeltaBytes": 4642476,
      "heapUsedBytes": 55615140,
      "domNodes": -260,
      "jsHeapTotalBytes": 16183296,
      "scriptDurationMs": 117.82700000000001,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2117.007000000001,
      "styleRecalcs": 68,
      "styleRecalcDurationMs": 16.854000000000003,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1215.279,
      "heapDeltaBytes": 15623948,
      "heapUsedBytes": 69028136,
      "domNodes": -263,
      "jsHeapTotalBytes": 17698816,
      "scriptDurationMs": 426.39399999999995,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2161.2499999999955,
      "styleRecalcs": 69,
      "styleRecalcDurationMs": 17.445,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1210.5609999999997,
      "heapDeltaBytes": 19305060,
      "heapUsedBytes": 71244496,
      "domNodes": -261,
      "jsHeapTotalBytes": 17698816,
      "scriptDurationMs": 428.61899999999997,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-pan",
      "durationMs": 2163.269000000014,
      "styleRecalcs": 68,
      "styleRecalcDurationMs": 16.064000000000004,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 1284.687,
      "heapDeltaBytes": 15864788,
      "heapUsedBytes": 69592060,
      "domNodes": -264,
      "jsHeapTotalBytes": 18485248,
      "scriptDurationMs": 483.554,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.699999999999818
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3199.6800000000007,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 17.833,
      "layouts": 60,
      "layoutDurationMs": 8.091000000000001,
      "taskDurationMs": 1451.291,
      "heapDeltaBytes": 10042720,
      "heapUsedBytes": 64930144,
      "domNodes": -267,
      "jsHeapTotalBytes": 15134720,
      "scriptDurationMs": 529.199,
      "eventListeners": -123,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3200.1410000000305,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 17.796999999999997,
      "layouts": 60,
      "layoutDurationMs": 8.31,
      "taskDurationMs": 1509.867,
      "heapDeltaBytes": 10023288,
      "heapUsedBytes": 65073852,
      "domNodes": -267,
      "jsHeapTotalBytes": 15503360,
      "scriptDurationMs": 567.681,
      "eventListeners": -123,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333335,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "large-graph-zoom",
      "durationMs": 3263.639000000012,
      "styleRecalcs": 65,
      "styleRecalcDurationMs": 18.012,
      "layouts": 60,
      "layoutDurationMs": 8.389000000000001,
      "taskDurationMs": 1495.107,
      "heapDeltaBytes": 10090700,
      "heapUsedBytes": 64716040,
      "domNodes": -265,
      "jsHeapTotalBytes": 16707584,
      "scriptDurationMs": 559.7090000000001,
      "eventListeners": -123,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "minimap-idle",
      "durationMs": 2054.846999999995,
      "styleRecalcs": 8,
      "styleRecalcDurationMs": 8.833,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 688.6619999999999,
      "heapDeltaBytes": 1875032,
      "heapUsedBytes": 55757540,
      "domNodes": -263,
      "jsHeapTotalBytes": 16445440,
      "scriptDurationMs": 120.767,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.659999999999975,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "minimap-idle",
      "durationMs": 2072.5020000000427,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 10.713999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 677.6990000000001,
      "heapDeltaBytes": 5066252,
      "heapUsedBytes": 57496440,
      "domNodes": -258,
      "jsHeapTotalBytes": 15921152,
      "scriptDurationMs": 137.49299999999997,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "minimap-idle",
      "durationMs": 2015.8010000000104,
      "styleRecalcs": 9,
      "styleRecalcDurationMs": 8.105999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 607.3519999999999,
      "heapDeltaBytes": 2156048,
      "heapUsedBytes": 56227264,
      "domNodes": -262,
      "jsHeapTotalBytes": 16183296,
      "scriptDurationMs": 113.515,
      "eventListeners": -127,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66333333333332,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 595.3420000000165,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 12.321,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 398.73499999999996,
      "heapDeltaBytes": 6750876,
      "heapUsedBytes": 49881740,
      "domNodes": 20,
      "jsHeapTotalBytes": 12845056,
      "scriptDurationMs": 139.58800000000002,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.663333333333338,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 606.1379999999872,
      "styleRecalcs": 47,
      "styleRecalcDurationMs": 12.876,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 394.685,
      "heapDeltaBytes": 6786080,
      "heapUsedBytes": 49932828,
      "domNodes": 20,
      "jsHeapTotalBytes": 12845056,
      "scriptDurationMs": 133.06,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 570.5590000000029,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 13.038,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 375.236,
      "heapDeltaBytes": 6543244,
      "heapUsedBytes": 50623896,
      "domNodes": 22,
      "jsHeapTotalBytes": 13107200,
      "scriptDurationMs": 129.27100000000002,
      "eventListeners": 8,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999727
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2024.2709999999988,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 10.690000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 433.09200000000004,
      "heapDeltaBytes": 20326012,
      "heapUsedBytes": 63375900,
      "domNodes": 20,
      "jsHeapTotalBytes": 23330816,
      "scriptDurationMs": 25.258000000000003,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2041.4910000000077,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 12.238000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 439.53600000000006,
      "heapDeltaBytes": 20333752,
      "heapUsedBytes": 63280220,
      "domNodes": 22,
      "jsHeapTotalBytes": 23592960,
      "scriptDurationMs": 25.83,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2021.2179999999762,
      "styleRecalcs": 10,
      "styleRecalcDurationMs": 10.367,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 371.63100000000003,
      "heapDeltaBytes": 19745356,
      "heapUsedBytes": 62953528,
      "domNodes": 20,
      "jsHeapTotalBytes": 23068672,
      "scriptDurationMs": 17.537000000000003,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.800000000000182
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1985.131999999993,
      "styleRecalcs": 85,
      "styleRecalcDurationMs": 54.864,
      "layouts": 16,
      "layoutDurationMs": 5.231999999999999,
      "taskDurationMs": 1012.5310000000001,
      "heapDeltaBytes": 11771900,
      "heapUsedBytes": 54843592,
      "domNodes": 74,
      "jsHeapTotalBytes": 22806528,
      "scriptDurationMs": 112.402,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1989.562000000035,
      "styleRecalcs": 88,
      "styleRecalcDurationMs": 55.340999999999994,
      "layouts": 16,
      "layoutDurationMs": 4.8069999999999995,
      "taskDurationMs": 1005.379,
      "heapDeltaBytes": 11832560,
      "heapUsedBytes": 54888348,
      "domNodes": 73,
      "jsHeapTotalBytes": 22806528,
      "scriptDurationMs": 117.64099999999999,
      "eventListeners": 6,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1690.7999999999674,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 39.041,
      "layouts": 16,
      "layoutDurationMs": 4.566,
      "taskDurationMs": 717.221,
      "heapDeltaBytes": 11507564,
      "heapUsedBytes": 54498172,
      "domNodes": 63,
      "jsHeapTotalBytes": 23330816,
      "scriptDurationMs": 107.795,
      "eventListeners": 4,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.66999999999998,
      "p95FrameDurationMs": 16.799999999999272
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8202.093999999988,
      "styleRecalcs": 250,
      "styleRecalcDurationMs": 46.25699999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4287.37,
      "heapDeltaBytes": 26602048,
      "heapUsedBytes": 77562680,
      "domNodes": -259,
      "jsHeapTotalBytes": 20844544,
      "scriptDurationMs": 1444.9699999999998,
      "eventListeners": -111,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8216.206999999997,
      "styleRecalcs": 251,
      "styleRecalcDurationMs": 48.587,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4205.394,
      "heapDeltaBytes": 25469040,
      "heapUsedBytes": 76274948,
      "domNodes": -259,
      "jsHeapTotalBytes": 18223104,
      "scriptDurationMs": 1410.421,
      "eventListeners": -111,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "viewport-pan-sweep",
      "durationMs": 8305.70399999999,
      "styleRecalcs": 251,
      "styleRecalcDurationMs": 47.905,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 4493.65,
      "heapDeltaBytes": 33897112,
      "heapUsedBytes": 84974488,
      "domNodes": -257,
      "jsHeapTotalBytes": 27922432,
      "scriptDurationMs": 1663.4250000000002,
      "eventListeners": -111,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 14120.470999999952,
      "styleRecalcs": 2,
      "styleRecalcDurationMs": 30.851000000000017,
      "layouts": 2,
      "layoutDurationMs": 10.774999999999993,
      "taskDurationMs": 14100.979,
      "heapDeltaBytes": 8513420,
      "heapUsedBytes": 166584404,
      "domNodes": -4997,
      "jsHeapTotalBytes": 56713216,
      "scriptDurationMs": 654.1250000000001,
      "eventListeners": 3526,
      "totalBlockingTimeMs": 950,
      "frameDurationMs": 17.780000000000047,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 13692.50199999999,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 13677.44,
      "heapDeltaBytes": -30753864,
      "heapUsedBytes": 165679016,
      "domNodes": -8331,
      "jsHeapTotalBytes": 27353088,
      "scriptDurationMs": 718.658,
      "eventListeners": -16460,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.216666666666665,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-idle",
      "durationMs": 13082.619000000022,
      "styleRecalcs": 0,
      "styleRecalcDurationMs": 0,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 13068.616000000002,
      "heapDeltaBytes": -36885540,
      "heapUsedBytes": 157744580,
      "domNodes": -8331,
      "jsHeapTotalBytes": 17391616,
      "scriptDurationMs": 658.2669999999999,
      "eventListeners": -16462,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.223333333333358,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 15362.899999999969,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 16.68700000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 15337.355000000001,
      "heapDeltaBytes": -58749200,
      "heapUsedBytes": 147763076,
      "domNodes": -8331,
      "jsHeapTotalBytes": -2793472,
      "scriptDurationMs": 945.636,
      "eventListeners": -16488,
      "totalBlockingTimeMs": 1,
      "frameDurationMs": 17.779999999999927,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 15694.40800000001,
      "styleRecalcs": 84,
      "styleRecalcDurationMs": 18.68700000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 15670.169000000002,
      "heapDeltaBytes": -22772188,
      "heapUsedBytes": 172278760,
      "domNodes": -8331,
      "jsHeapTotalBytes": 23072768,
      "scriptDurationMs": 1061.06,
      "eventListeners": -16453,
      "totalBlockingTimeMs": 5,
      "frameDurationMs": 17.223333333333358,
      "p95FrameDurationMs": 16.80000000000291
    },
    {
      "name": "vue-large-graph-pan",
      "durationMs": 15557.799000000046,
      "styleRecalcs": 78,
      "styleRecalcDurationMs": 17.436000000000007,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 15529.988,
      "heapDeltaBytes": -38583152,
      "heapUsedBytes": 171923832,
      "domNodes": -8331,
      "jsHeapTotalBytes": -6025216,
      "scriptDurationMs": 989.452,
      "eventListeners": -16456,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 17.776666666666642,
      "p95FrameDurationMs": 16.700000000000728
    },
    {
      "name": "workflow-execution",
      "durationMs": 457.8769999999963,
      "styleRecalcs": 19,
      "styleRecalcDurationMs": 25.336,
      "layouts": 5,
      "layoutDurationMs": 1.4839999999999995,
      "taskDurationMs": 135.481,
      "heapDeltaBytes": 4716484,
      "heapUsedBytes": 55027560,
      "domNodes": 169,
      "jsHeapTotalBytes": 262144,
      "scriptDurationMs": 31.25,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "workflow-execution",
      "durationMs": 447.4790000000439,
      "styleRecalcs": 18,
      "styleRecalcDurationMs": 26.206,
      "layouts": 5,
      "layoutDurationMs": 1.4130000000000003,
      "taskDurationMs": 129.806,
      "heapDeltaBytes": 4496792,
      "heapUsedBytes": 49131616,
      "domNodes": 156,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 30.96700000000001,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.700000000000273
    },
    {
      "name": "workflow-execution",
      "durationMs": 450.1239999999598,
      "styleRecalcs": 16,
      "styleRecalcDurationMs": 24.665,
      "layouts": 5,
      "layoutDurationMs": 1.3350000000000002,
      "taskDurationMs": 130.139,
      "heapDeltaBytes": 4487272,
      "heapUsedBytes": 48381196,
      "domNodes": 156,
      "jsHeapTotalBytes": 0,
      "scriptDurationMs": 30.924999999999997,
      "eventListeners": 71,
      "totalBlockingTimeMs": 0,
      "frameDurationMs": 16.666666666666668,
      "p95FrameDurationMs": 16.799999999999727
    }
  ]
}

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 29, 2026
@socket-security
Copy link
Copy Markdown

socket-security bot commented Mar 29, 2026

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
tools/test-recorder/src/transform/rules.ts (1)

38-39: ⚠️ Potential issue | 🟠 Major

Preserve non-page fixtures when rewriting async destructuring.

This replacement drops additional fixtures.
async ({ page, context }) becomes async ({ comfyPage }), which can break transformed tests that still use context (or others).

💡 Proposed fix
-    pattern: /async\s*\(\s*\{\s*page\s*(?:,\s*\w+\s*)*\}\s*\)/g,
-    replacement: 'async ({ comfyPage })',
+    pattern: /async\s*\(\s*\{\s*([^}]*\bpage\b[^}]*)\}\s*\)/g,
+    replacement: (_match, fixtures: string) => {
+      const mapped = fixtures
+        .split(',')
+        .map((fixture) => fixture.trim())
+        .filter(Boolean)
+        .map((fixture) => (fixture === 'page' ? 'comfyPage' : fixture))
+      return `async ({ ${mapped.join(', ')} })`
+    },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/test-recorder/src/transform/rules.ts` around lines 38 - 39, The current
rule (pattern/replacement) replaces any async destructured fixtures with 'async
({ comfyPage })', dropping other fixtures like 'context'; update the regex and
replacement in rules.ts so the pattern captures the full destructuring contents
and the replacement injects comfyPage while preserving all other keys (e.g.,
transform 'async ({ page, context })' into 'async ({ comfyPage, context })' or
'async ({ comfyPage })' when no others exist). Modify the existing pattern and
replacement to use capture groups for the inner object tokens (referencing
pattern and replacement in the diff) and reconstruct the destructuring to
include comfyPage plus the captured "rest" tokens so non-page fixtures are
preserved.
🧹 Nitpick comments (1)
tools/test-recorder/src/ui/logger.ts (1)

3-42: Optional: Add explicit void return types for documentation.

While the functions implicitly return void, explicit return types can improve IDE hints and serve as self-documentation. This is purely optional and a matter of style preference.

Example with explicit return type
-export function pass(label: string, detail?: string) {
+export function pass(label: string, detail?: string): void {
   const d = detail ? pc.dim(` ${detail}`) : ''
   console.log(`  ${pc.green('✅')} ${label}${d}`)
 }

Apply similar pattern to fail, warn, info, blank, header, and box.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/test-recorder/src/ui/logger.ts` around lines 3 - 42, Add explicit void
return types to the logger functions to improve IDE hints and
self-documentation: update the declarations for pass, fail, warn, info, blank,
header, and box to include ": void" (e.g., function pass(label: string, detail?:
string): void { ... }), leaving implementation unchanged; this is purely a type
annotation change so modify the function signatures only.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tools/test-recorder/src/ui/logger.ts`:
- Around line 34-42: The box function can throw when lines is empty because
Math.max(...lines.map(...)) becomes -Infinity; update box to guard against an
empty array by computing maxLen = lines.length ? Math.max(...lines.map(l =>
l.length)) : 0 (or return early when lines.length === 0), then build border and
pad using that safe maxLen; modify the box function to use this safe maxLen so
'─'.repeat(...) never receives a negative/invalid value.

---

Duplicate comments:
In `@tools/test-recorder/src/transform/rules.ts`:
- Around line 38-39: The current rule (pattern/replacement) replaces any async
destructured fixtures with 'async ({ comfyPage })', dropping other fixtures like
'context'; update the regex and replacement in rules.ts so the pattern captures
the full destructuring contents and the replacement injects comfyPage while
preserving all other keys (e.g., transform 'async ({ page, context })' into
'async ({ comfyPage, context })' or 'async ({ comfyPage })' when no others
exist). Modify the existing pattern and replacement to use capture groups for
the inner object tokens (referencing pattern and replacement in the diff) and
reconstruct the destructuring to include comfyPage plus the captured "rest"
tokens so non-page fixtures are preserved.

---

Nitpick comments:
In `@tools/test-recorder/src/ui/logger.ts`:
- Around line 3-42: Add explicit void return types to the logger functions to
improve IDE hints and self-documentation: update the declarations for pass,
fail, warn, info, blank, header, and box to include ": void" (e.g., function
pass(label: string, detail?: string): void { ... }), leaving implementation
unchanged; this is purely a type annotation change so modify the function
signatures only.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a6e78656-d021-4747-9ae2-fa0a13fc47de

📥 Commits

Reviewing files that changed from the base of the PR and between 589eb85 and a8bca8a.

📒 Files selected for processing (10)
  • .claude/skills/codegen-transform/SKILL.md
  • .gitignore
  • .mcp.json
  • .oxlintrc.json
  • browser_tests/AGENTS.md
  • knip.config.ts
  • tools/test-recorder/package.json
  • tools/test-recorder/src/transform/engine.ts
  • tools/test-recorder/src/transform/rules.ts
  • tools/test-recorder/src/ui/logger.ts
✅ Files skipped from review due to trivial changes (4)
  • .gitignore
  • browser_tests/AGENTS.md
  • knip.config.ts
  • tools/test-recorder/package.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • .oxlintrc.json
  • .mcp.json
  • .claude/skills/codegen-transform/SKILL.md

Comment on lines +34 to +42
export function box(lines: string[]) {
const maxLen = Math.max(...lines.map((l) => l.length))
const border = '─'.repeat(maxLen + 4)
console.log(` ┌${border}┐`)
for (const line of lines) {
console.log(` │ ${line.padEnd(maxLen + 2)}│`)
}
console.log(` └${border}┘`)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard against empty array in box().

If lines is empty, Math.max(...[]) returns -Infinity, causing '─'.repeat(-Infinity + 4) to throw a RangeError. Consider adding an early return or defaulting maxLen to 0.

🛡️ Proposed guard
 export function box(lines: string[]) {
+  if (lines.length === 0) return
   const maxLen = Math.max(...lines.map((l) => l.length))
   const border = '─'.repeat(maxLen + 4)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function box(lines: string[]) {
const maxLen = Math.max(...lines.map((l) => l.length))
const border = '─'.repeat(maxLen + 4)
console.log(` ┌${border}┐`)
for (const line of lines) {
console.log(` │ ${line.padEnd(maxLen + 2)}│`)
}
console.log(` └${border}┘`)
}
export function box(lines: string[]) {
if (lines.length === 0) return
const maxLen = Math.max(...lines.map((l) => l.length))
const border = '─'.repeat(maxLen + 4)
console.log(` ┌${border}┐`)
for (const line of lines) {
console.log(` │ ${line.padEnd(maxLen + 2)}│`)
}
console.log(` └${border}┘`)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/test-recorder/src/ui/logger.ts` around lines 34 - 42, The box function
can throw when lines is empty because Math.max(...lines.map(...)) becomes
-Infinity; update box to guard against an empty array by computing maxLen =
lines.length ? Math.max(...lines.map(l => l.length)) : 0 (or return early when
lines.length === 0), then build border and pad using that safe maxLen; modify
the box function to use this safe maxLen so '─'.repeat(...) never receives a
negative/invalid value.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
tools/test-recorder/src/transform/rules.ts (1)

38-40: ⚠️ Potential issue | 🟠 Major

Preserve non-page fixtures when rewriting async params.

This rewrite drops additional fixtures (e.g. context, request) by converting async ({ page, context }) into async ({ comfyPage }), which can break transformed tests.

Proposed fix
-    pattern: /async\s*\(\s*\{\s*page\s*(?:,\s*\w+\s*)*\}\s*\)/g,
-    replacement: 'async ({ comfyPage })',
+    pattern: /async\s*\(\s*\{\s*page(\s*(?:,\s*\w+\s*)*)\}\s*\)/g,
+    replacement: (_match, rest) => `async ({ comfyPage${rest} })`,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/test-recorder/src/transform/rules.ts` around lines 38 - 40, The current
rule in rules.ts that replaces pattern -> replacement drops other fixtures;
update the regex and replacement so you only rename the page param to comfyPage
while preserving surrounding fixtures: modify the pattern (currently named
pattern) to capture the contents of the object around the word "page" (e.g.
/async\s*\(\s*\{\s*([^}]*)\bpage\b([^}]*)\}\s*\)/g) and change replacement to
re-insert the captured groups while replacing only "page" with "comfyPage" (e.g.
'async ({ $1comfyPage$2 })' with spacing normalized); keep category: 'fixture'
unchanged and test with cases like async ({ page, context }), async ({ context,
page }), and async ({ page }) to ensure other fixtures are preserved.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@tools/test-recorder/src/transform/rules.ts`:
- Around line 38-40: The current rule in rules.ts that replaces pattern ->
replacement drops other fixtures; update the regex and replacement so you only
rename the page param to comfyPage while preserving surrounding fixtures: modify
the pattern (currently named pattern) to capture the contents of the object
around the word "page" (e.g. /async\s*\(\s*\{\s*([^}]*)\bpage\b([^}]*)\}\s*\)/g)
and change replacement to re-insert the captured groups while replacing only
"page" with "comfyPage" (e.g. 'async ({ $1comfyPage$2 })' with spacing
normalized); keep category: 'fixture' unchanged and test with cases like async
({ page, context }), async ({ context, page }), and async ({ page }) to ensure
other fixtures are preserved.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fb34ab05-0005-40a5-894b-e7adc368caf8

📥 Commits

Reviewing files that changed from the base of the PR and between a8bca8a and 9faccf5.

📒 Files selected for processing (2)
  • .claude/skills/codegen-transform/SKILL.md
  • tools/test-recorder/src/transform/rules.ts
✅ Files skipped from review due to trivial changes (1)
  • .claude/skills/codegen-transform/SKILL.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants