wenay-react2 1.0.47 → 1.0.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +14 -14
  2. package/doc/EXAMPLE_USAGE.md +969 -969
  3. package/doc/PROJECT_FUNCTIONALITY.md +403 -403
  4. package/doc/PROJECT_RULES.md +27 -27
  5. package/doc/WENAY_REACT2_RENAMES.md +170 -170
  6. package/doc/changes/v1.0.35.md +18 -18
  7. package/doc/changes/v1.0.38.md +37 -37
  8. package/doc/changes/v1.0.39.md +23 -23
  9. package/doc/changes/v1.0.40.md +14 -14
  10. package/doc/changes/v1.0.41.md +35 -35
  11. package/doc/changes/v1.0.42.md +26 -26
  12. package/doc/changes/v1.0.43.md +10 -10
  13. package/doc/changes/v1.0.44.md +14 -14
  14. package/doc/changes/v1.0.45.md +8 -8
  15. package/doc/changes/v1.0.46.md +11 -11
  16. package/doc/changes/v1.0.47.md +9 -9
  17. package/doc/changes/v1.0.48.md +8 -0
  18. package/doc/examples/README.md +4 -4
  19. package/doc/examples/peer-call-media.tsx +7 -7
  20. package/doc/examples/stand.tsx +5 -5
  21. package/doc/native.md +37 -37
  22. package/doc/progress/README.md +13 -13
  23. package/doc/progress/architecture-fix-queue.md +74 -74
  24. package/doc/progress/column-state-present-gate.md +28 -28
  25. package/doc/progress/common2-adoption-1.0.73.md +28 -28
  26. package/doc/progress/common2-adoption-1.0.74.md +24 -24
  27. package/doc/progress/hook-controller-opportunities.md +363 -363
  28. package/doc/progress/hook-extraction-audit.md +195 -195
  29. package/doc/progress/public-surface-normalization.md +351 -351
  30. package/doc/progress/qa-stand-walkthrough-2026-07-12.md +62 -0
  31. package/doc/progress/stand-as-examples-audit.md +20 -20
  32. package/doc/progress/style-system-normalization.md +121 -121
  33. package/doc/target/README.md +32 -32
  34. package/doc/target/my.md +122 -122
  35. package/doc/wenay-react2-rare.md +807 -807
  36. package/doc/wenay-react2.md +541 -541
  37. package/lib/common/demo/peerMedia.js +6 -1
  38. package/lib/common/src/logs/logsController.js +2 -2
  39. package/lib/common/testUseReact/qa.js +3 -3
  40. package/lib/style/menuRight.css +19 -19
  41. package/lib/style/style.css +23 -23
  42. package/lib/style/tokens.css +184 -184
  43. package/package.json +1 -1
  44. package/doc/wenay-react2-1.0.8.tgz +0 -0
@@ -1,195 +1,195 @@
1
- # Hook extraction audit (API-возвращающие хуки)
2
-
3
- Дата: 2026-07-09.
4
-
5
- Задача (надиктовка): пройти по всему коду фронт-библиотеки и осмысленно найти места,
6
- которые стоит вынести в `use*`/`create*` хуки, где хук **возвращает API** — методы,
7
- которые отдают X, Y, размеры, «сколько», snapshot и т.п. Не «работа ради работы»:
8
- каждый кандидат обязан устранять реальный императивный код/дублирование и иметь
9
- реального consumer (QA card / test / app), иначе он отклоняется.
10
-
11
- Метод: multi-agent проход. 7 finder-агентов по подсистемам (chart, menu, grid,
12
- dnd-geometry, replay-logs, settings/params/input, utils-core) → на каждый найденный
13
- кандидат отдельный adversarial critic (проверка фактов grep'ом, сверка с уже
14
- сделанным и запрещённым списком). Всего 27 агентов, 0 ошибок. Итог: 7 кандидатов
15
- прошли verify (3 do-now, 4 parked), 13 отклонено.
16
-
17
- Критерий осмысленности (из надиктовки): хочешь получить X,Y/размер/счётчик →
18
- правильный хук отдаёт **метод**, который это возвращает (`getSize()`, `getXY()`,
19
- `toPixel(v)`, `count()`, `isDirty()`). Не рефактор ради стиля.
20
-
21
- ## Сверка с уже сделанным / запрещённым
22
-
23
- Проход НЕ переоткрывает уже сделанное: `useKeyboard`, `useMiniLogsTable`,
24
- `useParamsEditorController`, `useSettingsDialogController`, `useFloatingWindowController`,
25
- `useRightMenuController`, `createLogsController`/`useLogsTableController`/
26
- `useLogsNotificationsController`, `useTextInputPanel`/`useFileInputPanel`, section/density
27
- registries, `createSearchHistory`, `createUiSlot`, `columnState` `createUpdateApi` и др.
28
- И НЕ предлагает запрещённое без consumer: `FResizableReact` hook, `memoryStore` core
29
- rewrite, `PageVisibilityProvider` в обычный UI, `StickerMenu` shared primitive, `DragBox`
30
- broad rewrite. QA card 25 (эталонный toolbar, ~qa.tsx:603) — не трогать.
31
-
32
- ---
33
-
34
- ## Прошли verify — DO NOW (3)
35
-
36
- ### 1. `useResizeObserver` / `useElementSize` — `MyResizeObserver.tsx`
37
-
38
- - Эффективность: medium; простота: simple; риск: low.
39
- - Императив сейчас: `CResizeObserver` — это класс + модульный синглтон
40
- `global_resizeObserver`, чисто side-effect (`add()`/`delete()`), **без React-хука**,
41
- который бы отдавал измерения.
42
- - Реальный consumer: `qa.tsx` `ResizeBugRepro` (объявлен ~1076, рендерится ~1723)
43
- вручную городит `new ResizeObserver` + `rAF` + `getBoundingClientRect` +
44
- `disconnect` в `useState`. Это **не** эталонная card 25.
45
- - Также `REFACTOR_PLAN.md` (строки 187/209/221/309) явно просит `useElementSize`
46
- вместо ручного `MyResizeObserver` цикла.
47
- - API, который вернёт хук: `{ width, height, getSize(), ref/bind }` — ровно «хочу
48
- размер → получаю метод/значение».
49
- - Подход: хук оборачивает существующий синглтон `CResizeObserver`, поэтому
50
- `setResizeableElement`/вызовы из `ParamsEditor` остаются нетронутыми → малый surface.
51
- - Оговорки verify: только один чистый consumer (QA card); упомянутые «места
52
- переиспользования» (FloatingWindow читает x/y для clamp, не размер; chart/agGrid
53
- имеют свои ResizeObserver, но сложные) чисто не переходят на width/height API —
54
- не завышать охват.
55
- - Проверка: `tsc` + `jest`; `ResizeBugRepro` переведён на хук, width/height
56
- обновляются при ресайзе на стенде; старый `setResizeableElement` путь не сломан.
57
-
58
- ### 2. `useLogsPageTable` / `useLogsFullTableController` — `logs.tsx`
59
-
60
- - Эффективность: medium; простота: medium; риск: medium.
61
- - Императив сейчас: `PageLogs` гоняет ag-grid императивно через `apiGrid` ref;
62
- блок importance-filter `setFilterModel` **написан дважды** (эффект `updateBy(setting)`
63
- ~92-103 И `onGridReady` ~160-167); `sizeColumnsToFit()` на update; `applyTransactionAsync`
64
- append (~105-112).
65
- - Реальный live consumer: `qa.tsx` card 9 (монтирует `<PageLogs />` ~94; assertion ~1765).
66
- - Это последняя logs-таблица, не переведённая на controller-паттерн (MiniLogs и
67
- `logsContext.LogsTable` — отдельные поверхности, уже сделаны).
68
- - API: `getApi()`, `fit()`, `applyImportanceFilter(min)`, `appendRow(row)`,
69
- `onGridReady`, `columnDefs`, `gridProps`. Дедуп filter-логики в один метод.
70
- - Подход: `PageLogs` остаётся тонким wrapper; row identity сохранить.
71
- - Проверка: card 9 + стенд, особое внимание filter-timing и `applyTransactionAsync` append.
72
-
73
- ### 3. `useCacheMapPersistence` — `cache.ts`
74
-
75
- - Эффективность: medium; простота: simple; риск: low.
76
- - Императив сейчас: тройное **точное** дублирование
77
- `useEffect(() => { void cache.load(); return cache.onDirty(() => cache.saveDebounced(300)); }, [])`
78
- в `qa.tsx`: `SettingsDialogDemo` (1221-1224), `UiSlotDemo` (1247-1251),
79
- `ToolbarDemo` (1329-1332). `ToolbarDemo` (~1320) — отдельная демка, **не** эталонная
80
- card 25 (та ~603).
81
- - Совпадает с задокументированным app-контрактом `doc/EXAMPLE_USAGE.md:85-99`,
82
- `doc/wenay-react2.md:54-63`.
83
- - API: `{ isDirty(), flush(), save(), reload() }`. Внимание: cache отдаёт `load()`,
84
- а не `reload()` — `reload()` сделать явным alias/ре-экспортом `load()`, не выдумывать
85
- несуществующий метод.
86
- - Границы: аддитивная обёртка, **НЕ** `memoryStore` rewrite; scope строго
87
- `load` + `onDirty`→`saveDebounced`, без pagehide/visibility flush.
88
- - Каждый сайт схлопывает ~2-3 строки — польза реальная, но скромная (поэтому
89
- medium, не high).
90
- - Проверка: card 20/21 и toolbar demo — persistence переживает reload; card 25 не трогать.
91
-
92
- ---
93
-
94
- ## Прошли verify — PARKED (4)
95
-
96
- Реальны, но сейчас не do-now; причина зафиксирована, вернуть при условии.
97
-
98
- ### `useChartCanvas` — `myChart/1/myChartTest.tsx`
99
- - Boilerplate реален (`ChartDemo`: `chartRef`+`containerRef`, `useEffect` с
100
- `createChartCanvas`/`appendData`/`jumpToEnd`/`setInterval`/`destroy`, кнопки через
101
- `chartRef.current?.method` null-check). `createChartCanvas` уже сам возвращает
102
- API-объект — хук лишь добавил бы lifecycle и стабильные non-null методы (паттерн
103
- как `useFloatingWindowController`). API: `containerRef, appendData, clearData,
104
- scrollX, zoomX, jumpToStart/End/Index, setAutoScaleY, setShowTimeAxis/PriceAxis, draw()`.
105
- - **Почему parked**: единственный consumer — сам example-компонент `ChartDemo`, который
106
- **не отрендерен ни в одной карточке/тесте** → нельзя проверить на стенде (working-style
107
- требует tsc+стенд). Польза чисто косметическая/демонстрационная.
108
- - Поправки к автору кандидата: `redraw()` не существует (в `IChartCanvas` это `draw()`);
109
- `ready` в интерфейсе нет — не тащить в API.
110
- - Вернуть как do-now, когда `ChartDemo` реально появится в карточке/тесте.
111
-
112
- ### `useContextMenuGesture` — `menuMouse.tsx`
113
- - Дублирование реально: gesture-распознавание (порог 0.05, long-press 300ms,
114
- right/dbl-click) в `menuMouse` `Layer` (~348-380) и в `menuR` `MenuR` (~55-107).
115
- - **Почему parked**: `menuR.MenuR` — **мёртвый код** (нет app-consumer; заявленный тест
116
- на самом деле импортит `RightMenu.tsx`, не `menuR`). Единственный live consumer —
117
- `Layer`. Делить хук с мёртвым кодом — мнимый выигрыш; честный фикс той половины —
118
- удалить `menuR`. Touch-семантика тонкая, card 4 гоняет только mouse-путь → риск
119
- touch-регрессии без нового consumer. Это часть уже-parked context-menu controller split.
120
- - Вернуть при: оживлении `menuR` с touch-тестами ИЛИ новом live touch-consumer.
121
-
122
- ### `columnState.api.reorderPreview(order, key, to)` — `columnState.ts`
123
- - Метод на существующем `createColumnState` контроллере (не новый хук): экспонировать
124
- move+fixed-pinning preview (+опц. `applyFixedPinning(order)`). Тройное дублирование
125
- идиомы `filter(!fixed)+pinFixed-splice`: `columnState.ts:140-145`,
126
- `ColumnsMenu.tsx:187-198`, `Toolbar.tsx:448-459`. Реальный consumer — `ColumnsMenu`
127
- (qa cards 30/31).
128
- - **Почему parked**: метод дедупит только 1 из 3 копий (копия `Toolbar` — другой
129
- контроллер над своими `opts.items`, честно вне охвата), и пересекается лишь pin-половина
130
- → польза low. Брать, если появится общий reorder-контракт для обоих контроллеров.
131
-
132
- ### `useResizeableFit` — `ParamsEditor.tsx`
133
- - 4x **байт-идентичный** inline ref-callback (`InputTime` 113-117, `InputList` 175-179,
134
- `InputNumber` 212-216, `InputListArray` 269-273): `setResizeableElement(el)` +
135
- `removeResizeableElement` cleanup. Consumer — `ParamsEditor` (qa cards 7 и 19).
136
- Также чинит minor unmount-dispose leak.
137
- - **Почему parked / поправка**: это **не** `use*`-хук — все 4 сайта внутри обычных
138
- функций-хелперов (`InputTime`/`InputList`/`InputNumber`/`InputListArray`), а не
139
- компонентов, там нельзя вызывать хуки. Правильная форма — общий **module-level
140
- стабильный bind callback-ref** (`bind(el)` ставит `setResizeableElement`, возвращает
141
- `()=>removeResizeableElement`). Не пересекается с done (`useParamsEditorController`
142
- покрывает только draft/notify) и forbidden (`FResizableReact` — другое). low risk,
143
- узкая польза — можно сделать как маленький shared primitive отдельным микро-passом.
144
-
145
- ---
146
-
147
- ## Отклонено (13) — кратко, для покрытия
148
-
149
- - `useChartEngine` (`chartEngineReact.tsx`) — **parked/не conscious**: императивная
150
- проводка реальна, но НИ ОДИН consumer не читает обратно координатный API
151
- (`xToPixel/pixelToValue/getViewport/getCrosshair/getPanelCount`); обе точки
152
- (`qa.tsx:1707` card 6, `use.tsx:187`) рендерят `<MyChartEngine/>` без пропов и ничего
153
- не считывают. Координатный хук был бы спекулятивным. Вернуть, если появится стенд/тест
154
- на chart canvas lifecycle или реальный consumer координат.
155
- - `useMenuPlacement` (`menu.tsx`) — **skip**: реальный `useLayoutEffect` + `getBoundingClientRect`,
156
- но ровно один in-file consumer и ноль дублирования; `RightMenu`/`LeftModal` клампят
157
- по другой семантике (parent rect / другая ось). Извлекать нечего дедуплицировать.
158
- - `useSidebarMenuController` (`LeftModal.tsx`) — **parked**: движок реален, но заявленные
159
- consumers ложны (в `use.tsx` — закомментированный блок; `Parameters.tsx` не импортит
160
- `LeftModal`). Нет live consumer. Совпадает с уже-parked LeftModal split.
161
- - `useStickerMenuDrag` (`StickerMenu.tsx`) — **skip** (overlap forbidden): drag реален,
162
- но consumer'ов нет (только barrel export + docs). `StickerMenu` в запрещённом списке.
163
- - `useColumnDotsGestures` (`ColumnDots.tsx`) — **skip**: жестовая логика реальна, но
164
- единственный consumer — card 29, второго нет. Извлечение = вью-модель без внешнего
165
- X/Y/size/count consumer.
166
- - `useCardModel` (`CardList.tsx`) — **skip**: single-use presentation-деривация (~15 строк),
167
- без дублирования, consumer только сам `CardList` (card 29). Спекулятивно.
168
- - `useDragArea` / `getXY on DragArea` (`DragArea.tsx`) — **skip** (overlap): у `DragArea`
169
- нет render-consumers (только export + docs); дублирует `useDraggable`. Мёртвая поверхность.
170
- - `createLogsStore` / `useLogsStore` (`logsContext.tsx`) — **parked** (overlap): store
171
- реален и дублирует `logsController`, но новых consumer'ов нет (только same-file демо +
172
- 1 unit-test). Это migration/deprecation-решение по `logsContext`, а не быстрый split.
173
- - `useInputAutoStep` (`ParamsEditor.tsx`) — **parked** (overlap): apply-only DOM behavior,
174
- 1 consumer (`InputNumber`), геттеров не читает; есть minor unmount-dispose leak (стоит
175
- починить точечно). Не тянет на API-хук.
176
- - `useNumericInputDraft` (`ParamsEditor.tsx`) — **parked**: WeakMap-черновик реален, но
177
- `InputNumber` вызывается как обычная функция (`InputNumber(set,val,range)`, не JSX) →
178
- хук внутри вызвать нельзя. Блокер до превращения `InputNumber` в компонент.
179
- - `useCallbackHubEffect` (`callbackHub.ts`) — **skip**: `createCallbackHub.on` уже
180
- возвращает unsubscribe, годный прямо в `useEffect`; обёртка не нужна; 1 demo-consumer.
181
- - `useObservableMap` (`observableMap.ts`) — **skip**: чистый 45-строчный data-layer,
182
- ноль UI-императива/дублирования; подписчики только внутренние + тесты.
183
- - `usePageVisibility` (`pageVisibilityContext.tsx`) — **parked** (overlap forbidden):
184
- дублирования нет (`PageVisibilityProvider` уже инкапсулирует listener); хук был бы просто
185
- `useContext`; consumer'ов ноль. В запрещённом «без consumer» списке.
186
-
187
- ## Рекомендованный порядок
188
-
189
- 1. `useCacheMapPersistence` — самый безопасный (simple/low), аддитивный, 3 реальных consumer.
190
- 2. `useResizeObserver`/`useElementSize` — simple/low, явный запрос в REFACTOR_PLAN + живой consumer.
191
- 3. `useLogsPageTable` — medium/medium, последняя logs-таблица вне controller-паттерна; делать аккуратно (filter-timing).
192
-
193
- Каждую задачу — по правилам `doc/target/README.md`: старое имя оставить compatibility
194
- wrapper, публичный API не менять, проверять `tsc -p tsconfig.qa-check.json --noEmit` +
195
- `jest` + сборку + стенд. Версию не бампать, не публиковать, не пушить.
1
+ # Hook extraction audit (API-возвращающие хуки)
2
+
3
+ Дата: 2026-07-09.
4
+
5
+ Задача (надиктовка): пройти по всему коду фронт-библиотеки и осмысленно найти места,
6
+ которые стоит вынести в `use*`/`create*` хуки, где хук **возвращает API** — методы,
7
+ которые отдают X, Y, размеры, «сколько», snapshot и т.п. Не «работа ради работы»:
8
+ каждый кандидат обязан устранять реальный императивный код/дублирование и иметь
9
+ реального consumer (QA card / test / app), иначе он отклоняется.
10
+
11
+ Метод: multi-agent проход. 7 finder-агентов по подсистемам (chart, menu, grid,
12
+ dnd-geometry, replay-logs, settings/params/input, utils-core) → на каждый найденный
13
+ кандидат отдельный adversarial critic (проверка фактов grep'ом, сверка с уже
14
+ сделанным и запрещённым списком). Всего 27 агентов, 0 ошибок. Итог: 7 кандидатов
15
+ прошли verify (3 do-now, 4 parked), 13 отклонено.
16
+
17
+ Критерий осмысленности (из надиктовки): хочешь получить X,Y/размер/счётчик →
18
+ правильный хук отдаёт **метод**, который это возвращает (`getSize()`, `getXY()`,
19
+ `toPixel(v)`, `count()`, `isDirty()`). Не рефактор ради стиля.
20
+
21
+ ## Сверка с уже сделанным / запрещённым
22
+
23
+ Проход НЕ переоткрывает уже сделанное: `useKeyboard`, `useMiniLogsTable`,
24
+ `useParamsEditorController`, `useSettingsDialogController`, `useFloatingWindowController`,
25
+ `useRightMenuController`, `createLogsController`/`useLogsTableController`/
26
+ `useLogsNotificationsController`, `useTextInputPanel`/`useFileInputPanel`, section/density
27
+ registries, `createSearchHistory`, `createUiSlot`, `columnState` `createUpdateApi` и др.
28
+ И НЕ предлагает запрещённое без consumer: `FResizableReact` hook, `memoryStore` core
29
+ rewrite, `PageVisibilityProvider` в обычный UI, `StickerMenu` shared primitive, `DragBox`
30
+ broad rewrite. QA card 25 (эталонный toolbar, ~qa.tsx:603) — не трогать.
31
+
32
+ ---
33
+
34
+ ## Прошли verify — DO NOW (3)
35
+
36
+ ### 1. `useResizeObserver` / `useElementSize` — `MyResizeObserver.tsx`
37
+
38
+ - Эффективность: medium; простота: simple; риск: low.
39
+ - Императив сейчас: `CResizeObserver` — это класс + модульный синглтон
40
+ `global_resizeObserver`, чисто side-effect (`add()`/`delete()`), **без React-хука**,
41
+ который бы отдавал измерения.
42
+ - Реальный consumer: `qa.tsx` `ResizeBugRepro` (объявлен ~1076, рендерится ~1723)
43
+ вручную городит `new ResizeObserver` + `rAF` + `getBoundingClientRect` +
44
+ `disconnect` в `useState`. Это **не** эталонная card 25.
45
+ - Также `REFACTOR_PLAN.md` (строки 187/209/221/309) явно просит `useElementSize`
46
+ вместо ручного `MyResizeObserver` цикла.
47
+ - API, который вернёт хук: `{ width, height, getSize(), ref/bind }` — ровно «хочу
48
+ размер → получаю метод/значение».
49
+ - Подход: хук оборачивает существующий синглтон `CResizeObserver`, поэтому
50
+ `setResizeableElement`/вызовы из `ParamsEditor` остаются нетронутыми → малый surface.
51
+ - Оговорки verify: только один чистый consumer (QA card); упомянутые «места
52
+ переиспользования» (FloatingWindow читает x/y для clamp, не размер; chart/agGrid
53
+ имеют свои ResizeObserver, но сложные) чисто не переходят на width/height API —
54
+ не завышать охват.
55
+ - Проверка: `tsc` + `jest`; `ResizeBugRepro` переведён на хук, width/height
56
+ обновляются при ресайзе на стенде; старый `setResizeableElement` путь не сломан.
57
+
58
+ ### 2. `useLogsPageTable` / `useLogsFullTableController` — `logs.tsx`
59
+
60
+ - Эффективность: medium; простота: medium; риск: medium.
61
+ - Императив сейчас: `PageLogs` гоняет ag-grid императивно через `apiGrid` ref;
62
+ блок importance-filter `setFilterModel` **написан дважды** (эффект `updateBy(setting)`
63
+ ~92-103 И `onGridReady` ~160-167); `sizeColumnsToFit()` на update; `applyTransactionAsync`
64
+ append (~105-112).
65
+ - Реальный live consumer: `qa.tsx` card 9 (монтирует `<PageLogs />` ~94; assertion ~1765).
66
+ - Это последняя logs-таблица, не переведённая на controller-паттерн (MiniLogs и
67
+ `logsContext.LogsTable` — отдельные поверхности, уже сделаны).
68
+ - API: `getApi()`, `fit()`, `applyImportanceFilter(min)`, `appendRow(row)`,
69
+ `onGridReady`, `columnDefs`, `gridProps`. Дедуп filter-логики в один метод.
70
+ - Подход: `PageLogs` остаётся тонким wrapper; row identity сохранить.
71
+ - Проверка: card 9 + стенд, особое внимание filter-timing и `applyTransactionAsync` append.
72
+
73
+ ### 3. `useCacheMapPersistence` — `cache.ts`
74
+
75
+ - Эффективность: medium; простота: simple; риск: low.
76
+ - Императив сейчас: тройное **точное** дублирование
77
+ `useEffect(() => { void cache.load(); return cache.onDirty(() => cache.saveDebounced(300)); }, [])`
78
+ в `qa.tsx`: `SettingsDialogDemo` (1221-1224), `UiSlotDemo` (1247-1251),
79
+ `ToolbarDemo` (1329-1332). `ToolbarDemo` (~1320) — отдельная демка, **не** эталонная
80
+ card 25 (та ~603).
81
+ - Совпадает с задокументированным app-контрактом `doc/EXAMPLE_USAGE.md:85-99`,
82
+ `doc/wenay-react2.md:54-63`.
83
+ - API: `{ isDirty(), flush(), save(), reload() }`. Внимание: cache отдаёт `load()`,
84
+ а не `reload()` — `reload()` сделать явным alias/ре-экспортом `load()`, не выдумывать
85
+ несуществующий метод.
86
+ - Границы: аддитивная обёртка, **НЕ** `memoryStore` rewrite; scope строго
87
+ `load` + `onDirty`→`saveDebounced`, без pagehide/visibility flush.
88
+ - Каждый сайт схлопывает ~2-3 строки — польза реальная, но скромная (поэтому
89
+ medium, не high).
90
+ - Проверка: card 20/21 и toolbar demo — persistence переживает reload; card 25 не трогать.
91
+
92
+ ---
93
+
94
+ ## Прошли verify — PARKED (4)
95
+
96
+ Реальны, но сейчас не do-now; причина зафиксирована, вернуть при условии.
97
+
98
+ ### `useChartCanvas` — `myChart/1/myChartTest.tsx`
99
+ - Boilerplate реален (`ChartDemo`: `chartRef`+`containerRef`, `useEffect` с
100
+ `createChartCanvas`/`appendData`/`jumpToEnd`/`setInterval`/`destroy`, кнопки через
101
+ `chartRef.current?.method` null-check). `createChartCanvas` уже сам возвращает
102
+ API-объект — хук лишь добавил бы lifecycle и стабильные non-null методы (паттерн
103
+ как `useFloatingWindowController`). API: `containerRef, appendData, clearData,
104
+ scrollX, zoomX, jumpToStart/End/Index, setAutoScaleY, setShowTimeAxis/PriceAxis, draw()`.
105
+ - **Почему parked**: единственный consumer — сам example-компонент `ChartDemo`, который
106
+ **не отрендерен ни в одной карточке/тесте** → нельзя проверить на стенде (working-style
107
+ требует tsc+стенд). Польза чисто косметическая/демонстрационная.
108
+ - Поправки к автору кандидата: `redraw()` не существует (в `IChartCanvas` это `draw()`);
109
+ `ready` в интерфейсе нет — не тащить в API.
110
+ - Вернуть как do-now, когда `ChartDemo` реально появится в карточке/тесте.
111
+
112
+ ### `useContextMenuGesture` — `menuMouse.tsx`
113
+ - Дублирование реально: gesture-распознавание (порог 0.05, long-press 300ms,
114
+ right/dbl-click) в `menuMouse` `Layer` (~348-380) и в `menuR` `MenuR` (~55-107).
115
+ - **Почему parked**: `menuR.MenuR` — **мёртвый код** (нет app-consumer; заявленный тест
116
+ на самом деле импортит `RightMenu.tsx`, не `menuR`). Единственный live consumer —
117
+ `Layer`. Делить хук с мёртвым кодом — мнимый выигрыш; честный фикс той половины —
118
+ удалить `menuR`. Touch-семантика тонкая, card 4 гоняет только mouse-путь → риск
119
+ touch-регрессии без нового consumer. Это часть уже-parked context-menu controller split.
120
+ - Вернуть при: оживлении `menuR` с touch-тестами ИЛИ новом live touch-consumer.
121
+
122
+ ### `columnState.api.reorderPreview(order, key, to)` — `columnState.ts`
123
+ - Метод на существующем `createColumnState` контроллере (не новый хук): экспонировать
124
+ move+fixed-pinning preview (+опц. `applyFixedPinning(order)`). Тройное дублирование
125
+ идиомы `filter(!fixed)+pinFixed-splice`: `columnState.ts:140-145`,
126
+ `ColumnsMenu.tsx:187-198`, `Toolbar.tsx:448-459`. Реальный consumer — `ColumnsMenu`
127
+ (qa cards 30/31).
128
+ - **Почему parked**: метод дедупит только 1 из 3 копий (копия `Toolbar` — другой
129
+ контроллер над своими `opts.items`, честно вне охвата), и пересекается лишь pin-половина
130
+ → польза low. Брать, если появится общий reorder-контракт для обоих контроллеров.
131
+
132
+ ### `useResizeableFit` — `ParamsEditor.tsx`
133
+ - 4x **байт-идентичный** inline ref-callback (`InputTime` 113-117, `InputList` 175-179,
134
+ `InputNumber` 212-216, `InputListArray` 269-273): `setResizeableElement(el)` +
135
+ `removeResizeableElement` cleanup. Consumer — `ParamsEditor` (qa cards 7 и 19).
136
+ Также чинит minor unmount-dispose leak.
137
+ - **Почему parked / поправка**: это **не** `use*`-хук — все 4 сайта внутри обычных
138
+ функций-хелперов (`InputTime`/`InputList`/`InputNumber`/`InputListArray`), а не
139
+ компонентов, там нельзя вызывать хуки. Правильная форма — общий **module-level
140
+ стабильный bind callback-ref** (`bind(el)` ставит `setResizeableElement`, возвращает
141
+ `()=>removeResizeableElement`). Не пересекается с done (`useParamsEditorController`
142
+ покрывает только draft/notify) и forbidden (`FResizableReact` — другое). low risk,
143
+ узкая польза — можно сделать как маленький shared primitive отдельным микро-passом.
144
+
145
+ ---
146
+
147
+ ## Отклонено (13) — кратко, для покрытия
148
+
149
+ - `useChartEngine` (`chartEngineReact.tsx`) — **parked/не conscious**: императивная
150
+ проводка реальна, но НИ ОДИН consumer не читает обратно координатный API
151
+ (`xToPixel/pixelToValue/getViewport/getCrosshair/getPanelCount`); обе точки
152
+ (`qa.tsx:1707` card 6, `use.tsx:187`) рендерят `<MyChartEngine/>` без пропов и ничего
153
+ не считывают. Координатный хук был бы спекулятивным. Вернуть, если появится стенд/тест
154
+ на chart canvas lifecycle или реальный consumer координат.
155
+ - `useMenuPlacement` (`menu.tsx`) — **skip**: реальный `useLayoutEffect` + `getBoundingClientRect`,
156
+ но ровно один in-file consumer и ноль дублирования; `RightMenu`/`LeftModal` клампят
157
+ по другой семантике (parent rect / другая ось). Извлекать нечего дедуплицировать.
158
+ - `useSidebarMenuController` (`LeftModal.tsx`) — **parked**: движок реален, но заявленные
159
+ consumers ложны (в `use.tsx` — закомментированный блок; `Parameters.tsx` не импортит
160
+ `LeftModal`). Нет live consumer. Совпадает с уже-parked LeftModal split.
161
+ - `useStickerMenuDrag` (`StickerMenu.tsx`) — **skip** (overlap forbidden): drag реален,
162
+ но consumer'ов нет (только barrel export + docs). `StickerMenu` в запрещённом списке.
163
+ - `useColumnDotsGestures` (`ColumnDots.tsx`) — **skip**: жестовая логика реальна, но
164
+ единственный consumer — card 29, второго нет. Извлечение = вью-модель без внешнего
165
+ X/Y/size/count consumer.
166
+ - `useCardModel` (`CardList.tsx`) — **skip**: single-use presentation-деривация (~15 строк),
167
+ без дублирования, consumer только сам `CardList` (card 29). Спекулятивно.
168
+ - `useDragArea` / `getXY on DragArea` (`DragArea.tsx`) — **skip** (overlap): у `DragArea`
169
+ нет render-consumers (только export + docs); дублирует `useDraggable`. Мёртвая поверхность.
170
+ - `createLogsStore` / `useLogsStore` (`logsContext.tsx`) — **parked** (overlap): store
171
+ реален и дублирует `logsController`, но новых consumer'ов нет (только same-file демо +
172
+ 1 unit-test). Это migration/deprecation-решение по `logsContext`, а не быстрый split.
173
+ - `useInputAutoStep` (`ParamsEditor.tsx`) — **parked** (overlap): apply-only DOM behavior,
174
+ 1 consumer (`InputNumber`), геттеров не читает; есть minor unmount-dispose leak (стоит
175
+ починить точечно). Не тянет на API-хук.
176
+ - `useNumericInputDraft` (`ParamsEditor.tsx`) — **parked**: WeakMap-черновик реален, но
177
+ `InputNumber` вызывается как обычная функция (`InputNumber(set,val,range)`, не JSX) →
178
+ хук внутри вызвать нельзя. Блокер до превращения `InputNumber` в компонент.
179
+ - `useCallbackHubEffect` (`callbackHub.ts`) — **skip**: `createCallbackHub.on` уже
180
+ возвращает unsubscribe, годный прямо в `useEffect`; обёртка не нужна; 1 demo-consumer.
181
+ - `useObservableMap` (`observableMap.ts`) — **skip**: чистый 45-строчный data-layer,
182
+ ноль UI-императива/дублирования; подписчики только внутренние + тесты.
183
+ - `usePageVisibility` (`pageVisibilityContext.tsx`) — **parked** (overlap forbidden):
184
+ дублирования нет (`PageVisibilityProvider` уже инкапсулирует listener); хук был бы просто
185
+ `useContext`; consumer'ов ноль. В запрещённом «без consumer» списке.
186
+
187
+ ## Рекомендованный порядок
188
+
189
+ 1. `useCacheMapPersistence` — самый безопасный (simple/low), аддитивный, 3 реальных consumer.
190
+ 2. `useResizeObserver`/`useElementSize` — simple/low, явный запрос в REFACTOR_PLAN + живой consumer.
191
+ 3. `useLogsPageTable` — medium/medium, последняя logs-таблица вне controller-паттерна; делать аккуратно (filter-timing).
192
+
193
+ Каждую задачу — по правилам `doc/target/README.md`: старое имя оставить compatibility
194
+ wrapper, публичный API не менять, проверять `tsc -p tsconfig.qa-check.json --noEmit` +
195
+ `jest` + сборку + стенд. Версию не бампать, не публиковать, не пушить.