Skip to content

components: fix and improve change detection recording from the October 2026 audit #316

Closed as duplicate

Description

@erkamyaman

Context

This comes from a code audit of change detection recording (cd-overlay.ts, cd-recorder.ts, change-detection.ts, rpc/cd-tools.ts, app/src/pages/cd-recording.ts). The audit was done in October 2026 while comparing Pangular with other devtools. Roadmap items live in #310, #311, #312 and #313. Items marked (to confirm) were not reproduced.

Problems

Medium

  • A second start wipes a running recording: setRecording(true) calls recorder.start() every time, and start() calls reset(). An agent record: "start" with no page is broadcast to every tab, so it erases the user's panel recording. A double click does the same. Make on: true a no-op when already recording, and clear only on clear: true. Consider requiring page for agent start and clear when more than one tab is connected (packages/devtools/src/cd-overlay.ts:56-61, packages/devtools/src/cd-recorder.ts:228-232, packages/devtools/src/devframe.ts:1949-1954).
  • Stale output trigger: lastOutput stays set until the next ChangeDetectionStart. An output that started no tick (zoneless with no signal change, or an output nobody listens to) is then credited to a later tick caused by a timer, HTTP or a signal. Stamp lastOutput with now() and drop it when change detection starts more than about one frame later, or clear it in a microtask after the output ends (packages/devtools/src/cd-recorder.ts:119-132).

Low

  • Wrong "needs Angular 20" message: supported becomes false whenever addProfilerListener returns null. That also happens when ng is not available yet, when the page has no [ng-version] (createApplication, Angular Elements, where angularMajor returns 0), or when ɵsetProfiler throws. The panel and the agent tool then show a fixed "needs Angular 20" text, and nothing retries until the user toggles again. Report a reason (no-ng-yet, angular<20, no-profiler-api), retry the attach on the next refresh while recording is wanted, and read the version another way when ng-version is missing (packages/devtools/src/cd-overlay.ts:58-60, packages/devtools/src/change-detection.ts:55-59, app/src/pages/cd-recording.ts:66-68, packages/devtools/src/rpc/cd-tools.ts:161-163).
  • Start is confirmed without an answer from the page: change-detection-record is broadcast with optional: true, and the panel and agent tool say "Recording started" as soon as the hub accepts the request. "Could not reach the page" only shows when the hub itself fails. Wait up to about 1 s for a push with recording: true (or supported: false) from that pageId, and say when the page did not answer (packages/devtools/src/devframe.ts:1256-1263, packages/devtools/src/devframe.ts:1955-1961, app/src/pages/cd-recording.ts:313-332).
  • Limits are hit silently: totals stop taking new classes at 1000, host WeakRefs stop at 2000 instances, and a failed getHostElement is cached as null forever. Tree badges and totals then go missing with no note, unlike cycles, which carry dropped. Add droppedClasses and droppedHosts to CdRecording, show them in LimitNote and the agent text, and do not cache a null host id (packages/devtools/src/cd-recorder.ts:165, packages/devtools/src/cd-recorder.ts:180-187, packages/devtools/src/cd-overlay.ts:42-54).
  • Nested tick replaces the cycle in progress: a ChangeDetectionStart while current is set overwrites it and resets the frame stack, so the outer cycle is lost. Keep a cycle stack, or count a nested tick as a pass (packages/devtools/src/cd-recorder.ts:122-133) (to confirm).
  • Panel shows less than the agent tool: the agent answer has a "Most often checked" list, the panel does not. Cycle rows can't be expanded to their top 10 components, component names don't link to their tree row or highlight, and the zone mode is not shown next to Record. The slowest table uses track $index instead of c.name (app/src/pages/cd-recording.ts:75-126, app/src/pages/cd-recording.ts:89, packages/devtools/src/rpc/cd-tools.ts:171-186).
  • Duplicated types: the panel declares CdCheck, CdCycle, CdComponentStat and CdPage again instead of importing them, so the copies can drift without a compile error. Export them from @pangular-inspector/devtools/config (or a shared types entry), as limit-note.ts and network-inspector.ts already do (app/src/pages/cd-recording.ts:8-38, packages/devtools/src/cd-recorder.ts:17-53, packages/devtools/src/cd-overlay.ts:18-22).

Improvements

  • Keep recording across a reload: store a "recording wanted" flag in sessionStorage per pageId, like storedInstrumented() does for the router, so a reload profile with bootstrap and the first cycles can be captured (packages/devtools/src/cd-overlay.ts, packages/devtools/src/router-actions.ts:91).
  • Slow cycle budget: add limits.cdSlowMs (default 16 ms). Highlight cycles over budget in the panel and count them in the agent answer, so an agent can check "no frame-dropping ticks" after a change (packages/devtools/src/config.ts, packages/devtools/src/rpc/cd-tools.ts, app/src/pages/cd-recording.ts).

Already tracked elsewhere

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or shows wrong datafeatureA feature request or a pull request that adds one

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions