Files
kandev/docs/plans/plan-bubble-menu-transaction-loop/plan.md
T
2026-08-27 12:05:22 +00:00

4.2 KiB

created, status, requirements, system_design, legacy_specs
created status requirements system_design legacy_specs
2026-08-27 done
REQ-UI-RESPONSIVE-PLAN-FORMATTING-001
../../specs/ui/system-design/responsive-plan-formatting.md

Implementation Plan: Stop the Plan Bubble Menu Transaction Loop

Overview

Stop the desktop Plan editor from running a continuous React and Tiptap transaction loop. Implement one focused TDD work order because the fault and its regression boundary are in one component.

The trace shows approximately 44,800 React scheduler callbacks in 3.56 seconds. The DOM stays at 4,862 elements. The source-mapped stack shows a Tiptap BubbleMenu option update followed by an editor transaction and another PlanBubbleMenu render.

Scope

In scope

  • Keep the desktop BubbleMenu option identity stable across unchanged renders.
  • Publish a new editor snapshot only when its derived values change.
  • Add a focused regression that models the real BubbleMenu option-update transaction.
  • Preserve the desktop selection bubble and the mobile docked formatting strip.

Out of scope

  • Change Plan formatting commands, layout, touch geometry, or viewport behavior.
  • Change Tiptap, ProseMirror, task persistence, or WebSocket code.
  • Add performance telemetry or a general React render monitor.
  • Change the public plugin editor contract.

Technical approach

Stable BubbleMenu inputs

Define the placement options once in apps/web/components/editors/tiptap/plan-bubble-menu.tsx. Pass that stable object to the desktop BubbleMenu.

Deduplicated editor snapshots

Compare the next EditorSnapshot with the current snapshot. Return the current state when all derived values are equal. Publish the next snapshot only after focus, selection, context, or active marks change.

Regression boundary

Extend plan-bubble-menu.test.tsx with a controlled BubbleMenu fake. The fake models Tiptap's option dependency and its metadata transaction. The test fails on the current code because the transaction repeats after each render.

Tests

Acceptance criterion Evidence
AC-UI-RESPONSIVE-PLAN-FORMATTING-001.1 The focused Vitest regression proves that the desktop BubbleMenu settles after one option update. Focus, selection, active-mark, and desktop/mobile code-block transitions remain reactive.
AC-UI-RESPONSIVE-PLAN-FORMATTING-001.2 through .8 The existing mobile component tests and mobile-plan-formatting-toolbar.spec.ts prove that the docked presentation keeps its current behavior.

E2E tests

This fix changes render-state normalization only. It does not change layout, touch behavior, scrolling, navigation, or viewport-dependent interaction.

The existing mobile-plan-formatting-toolbar.spec.ts remains the mobile parity evidence. Run its mobile-chrome scenario after the focused unit test.

Work orders

Verification results

  • Red regression: the controlled BubbleMenu fake observed four option-update transactions before the fix and failed the settlement assertion.
  • cd apps/web && pnpm exec vitest run components/editors/tiptap/plan-bubble-menu.test.tsx passed, 13 tests, including active-mark and code-block transaction changes.
  • cd apps/web && pnpm run typecheck passed.
  • cd apps/web && pnpm exec eslint components/editors/tiptap/plan-bubble-menu.tsx components/editors/tiptap/plan-bubble-menu.test.tsx passed.
  • cd apps/web && pnpm e2e:run --project mobile-chrome tests/task/mobile-plan-formatting-toolbar.spec.ts passed, 1 test.
  • Fresh desktop and mobile PR screenshots were captured, inspected, validated, and compressed. The disposable desktop capture spec was removed.

Risks

  • An incomplete snapshot comparison can leave pressed formatting state stale.
  • An unstable BubbleMenu prop can reintroduce metadata transactions on each render.
  • A weak menu mock can hide the Tiptap effect that caused the fault.

Public documentation

None. This fix changes no public command, configuration, API, workflow, or plugin contract.

Decisions

No ADR is required. The fix completes the current component design without a new ownership or public contract boundary.