4.2 KiB
created, status, requirements, system_design, legacy_specs
| created | status | requirements | system_design | legacy_specs | ||
|---|---|---|---|---|---|---|
| 2026-08-27 | done |
|
|
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.tsxpassed, 13 tests, including active-mark and code-block transaction changes.cd apps/web && pnpm run typecheckpassed.cd apps/web && pnpm exec eslint components/editors/tiptap/plan-bubble-menu.tsx components/editors/tiptap/plan-bubble-menu.test.tsxpassed.cd apps/web && pnpm e2e:run --project mobile-chrome tests/task/mobile-plan-formatting-toolbar.spec.tspassed, 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.