AURORA-1848: лист и своды без null-полей + фронт (B) #242

Open
aep wants to merge 9 commits from feat/233-aurora-1848-sheet-json-no-pydantic-b into feat/233-aurora-1848-sheet-json-no-pydantic
Owner

Не мержить до merge PR A (#239) и PR #223 (AURORA-1838). Ветка содержит merge-коммит #223; после их merge ветка перебазируется на test, коммиты #223 уйдут из диффа.

Closes #233. Jira AURORA-1848 (эпик AURORA-1834). Стек на PR A (#239).

Что сделано

  • Бэк: у листа формы и сводов 1/2 в data нет null-полей (jsonb_strip_nulls(data) внутри json_build_object(...)::text).
  • Фронт: тесты updateCells на отсутствующие ключи (версия #223 достаточна, cellUtils.js не менялся), cell_updated всегда несёт value (undefined -> null, messageUtils.js), getDataRowId возвращает null (после strip у групповых строк нет line_id, иначе row_deleted уходил без row_id и сервер рвал WebSocket, I-3).
  • perf/perfkit/gen/grow.py: form4_ids не падает на ответах без null-полей.
  • Аудит null/undefined на фронте (31 место, без дефектов; добавлена проверка полезной нагрузки WebSocket): .superpowers/sdd/.../task-15-report.md.

BREAKING для потребителя, который отличает «ключ есть и равен null» от «ключа нет»: в data листа и сводов 1/2 нет null-полей (на любой глубине; {} и null в массивах остаются). Отчёты проектов, ответы путей записи (PATCH отдаёт null явно) и WebSocket — как раньше. Выгрузка Excel не меняется. Поведение jsonb_strip_nulls проверено вручную на PG 15.12 и 16.15: идентично.
test_summary2_sheets_smoke ослаблять не пришлось.
TanStack Table в dev-сборке пишет console.warn для undefined во вложенном accessorKey — не исправляем, в prod нет. EditCell.jsx:223 <textarea value={undefined}> — аналогичное dev-предупреждение, deferred.
X-DB-Time-Ms в B включает стоимость jsonb_strip_nulls: доля Python в A и B напрямую не сопоставима.

Тесты

  • Бэк (PG16, dfip_1848): 3 failed (те же 3 известных на test), 248 passed, 4 skipped. PG 15.12 (ветка + AURORA-1922): 3 failed (те же), 250 passed, 4 skipped.
  • Фронт: node --test utils/*.test.js 31/31 (по отчёту исполнителя), npm run build успешен; biome: добавленные файлы чисты, ошибки только в файлах из #223 / старых тестах.
  • perf -m "not stand": 3 failed в test_run_all.py (есть и на origin/test).

Чек-лист ручной проверки (D6)

  • FORM_2/AHR: второй пользователь заполняет пустую ячейку — первый видит значение без перезагрузки; то же с очисткой
  • вход в пустую ячейку и выход без ввода — без ошибки
  • выбрать групповую строку -> Удалить: сообщение об ошибке, соединение не рвётся (I-3)
  • свод 2: пустые ячейки «—», поиск работает; свод 1 открывается
  • отчёт проекта не изменился
  • сценарий соавтора на стенде PERF_TARGETS='FORM_2/AHR/*' PERF_COAUTHOR_RATES=1 PERF_REPEATS=1, page_ws_updates > 0 (выполняет контроллер)
  • до merge: compare_responses.py compare --mode strip-nulls на стенде; PG15 (проверено, см. комментарий)

Замер до/после — добавит контроллер после прогона на стенде. Пороги (свод 2 GO -30 %, FORM_2/AHR -10 % и меньший распакованный размер) не условие мержа, недобор — follow-up. openspec archive aurora-1848-sheet-json — только после merge B.

Rulings I made

  • R-6 (design #6): PATCH null в тесте — сначала 225, затем null.
  • R-7 (design #7): getDataRowId -> null вместо undefined.
  • R-8 (design #8): аудит дополнен проверкой полезной нагрузки WebSocket.
    (Рулинги R-1..R-5 фазы A — в PR #239.)

Находки

Маркер Суть Статус
T11.1 комментарий: тест «q1 без m1» — регрессионный, на test зелёный deferred
T11.2 тест «два обновления одной строки на замороженных данных» fixed c859ca1 (= M-8)
T13.1 test_patch_cell_null_is_explicit зависит от созданного им состояния (откат сессией) rejected
T13.2 длинные строки >120 rejected (стиль)
T15.1 EditCell.jsx:223 <textarea value={undefined}> — dev-предупреждение React при первом вводе deferred
T15.2 вложенный accessorKey с undefined — dev-предупреждение TanStack (в prod нет) rejected (design)
I-3 удаление групповой строки слало row_deleted без row_id (getDataRowId вернул undefined после strip), сервер падал на data["data"]["row_id"] и рвал WebSocket fixed c859ca1
M-7 buildCellUpdatedMessage нормализует только value rejected (INPUT-строки only; покрыто фиксом I-3)
M-8 нет теста глубоко вложенного отсутствующего блока fixed c859ca1
M-9 нет теста jsonb_strip_nulls на литерале против _strip_nulls fixed c859ca1
M-10 X-DB-Time-Ms в B включает стоимость jsonb_strip_nulls: доля Python в A и B не сопоставима напрямую deferred (оговорка рядом с замерами)
R-6 (design #6) PATCH null: сначала 225, затем null fixed (решение)
R-7 (design #7) getDataRowId возвращает null fixed c859ca1
R-8 (design #8) аудит Task 15 дополнен проверкой полезной нагрузки WebSocket fixed (решение)
O-6 на origin/test cellUtils.js импортирует './rowUtils' без .js — красный шаг требовал временной правки; тест «q1 без m1» зелёный и на test rejected
O-7 ошибки biome в файлах #223 (cellUtils.js, cellUtils.test.js:10,23, useWebSocket.js) и в старом тесте rowUtils.test.js:17-19 rejected (не наши)

Отложенное (deferred): T11.1, T15.1, M-10; из A: T5.2, T6.2, T7.4, T7.6, M-2, O-3 (rf-rollup r.year).

🤖 Generated with Claude Code

**Не мержить до merge PR A (#239) и PR #223 (AURORA-1838). Ветка содержит merge-коммит #223; после их merge ветка перебазируется на `test`, коммиты #223 уйдут из диффа.** Closes #233. Jira AURORA-1848 (эпик AURORA-1834). Стек на PR A (#239). ## Что сделано - Бэк: у листа формы и сводов 1/2 в `data` нет null-полей (`jsonb_strip_nulls(data)` внутри `json_build_object(...)::text`). - Фронт: тесты `updateCells` на отсутствующие ключи (версия #223 достаточна, `cellUtils.js` не менялся), `cell_updated` всегда несёт `value` (`undefined` -> `null`, `messageUtils.js`), `getDataRowId` возвращает `null` (после strip у групповых строк нет `line_id`, иначе `row_deleted` уходил без `row_id` и сервер рвал WebSocket, I-3). - `perf/perfkit/gen/grow.py`: `form4_ids` не падает на ответах без null-полей. - Аудит null/undefined на фронте (31 место, без дефектов; добавлена проверка полезной нагрузки WebSocket): .superpowers/sdd/.../task-15-report.md. **BREAKING** для потребителя, который отличает «ключ есть и равен null» от «ключа нет»: в `data` листа и сводов 1/2 нет null-полей (на любой глубине; `{}` и null в массивах остаются). Отчёты проектов, ответы путей записи (PATCH отдаёт null явно) и WebSocket — как раньше. Выгрузка Excel не меняется. Поведение `jsonb_strip_nulls` проверено вручную на PG 15.12 и 16.15: идентично. `test_summary2_sheets_smoke` ослаблять не пришлось. TanStack Table в dev-сборке пишет `console.warn` для `undefined` во вложенном `accessorKey` — не исправляем, в prod нет. `EditCell.jsx:223` `<textarea value={undefined}>` — аналогичное dev-предупреждение, deferred. `X-DB-Time-Ms` в B включает стоимость `jsonb_strip_nulls`: доля Python в A и B напрямую не сопоставима. ## Тесты - Бэк (PG16, dfip_1848): 3 failed (те же 3 известных на test), 248 passed, 4 skipped. PG 15.12 (ветка + AURORA-1922): 3 failed (те же), 250 passed, 4 skipped. - Фронт: `node --test utils/*.test.js` 31/31 (по отчёту исполнителя), `npm run build` успешен; biome: добавленные файлы чисты, ошибки только в файлах из #223 / старых тестах. - perf `-m "not stand"`: 3 failed в test_run_all.py (есть и на origin/test). ## Чек-лист ручной проверки (D6) - [ ] FORM_2/AHR: второй пользователь заполняет пустую ячейку — первый видит значение без перезагрузки; то же с очисткой - [ ] вход в пустую ячейку и выход без ввода — без ошибки - [ ] выбрать групповую строку -> Удалить: сообщение об ошибке, соединение не рвётся (I-3) - [ ] свод 2: пустые ячейки «—», поиск работает; свод 1 открывается - [ ] отчёт проекта не изменился - [ ] сценарий соавтора на стенде `PERF_TARGETS='FORM_2/AHR/*' PERF_COAUTHOR_RATES=1 PERF_REPEATS=1`, `page_ws_updates > 0` (выполняет контроллер) - [ ] до merge: `compare_responses.py compare --mode strip-nulls` на стенде; PG15 (проверено, см. комментарий) Замер до/после — добавит контроллер после прогона на стенде. Пороги (свод 2 GO -30 %, FORM_2/AHR -10 % и меньший распакованный размер) не условие мержа, недобор — follow-up. `openspec archive aurora-1848-sheet-json` — только после merge B. ## Rulings I made - R-6 (design #6): PATCH null в тесте — сначала 225, затем null. - R-7 (design #7): `getDataRowId` -> `null` вместо `undefined`. - R-8 (design #8): аудит дополнен проверкой полезной нагрузки WebSocket. (Рулинги R-1..R-5 фазы A — в PR #239.) ## Находки | Маркер | Суть | Статус | |---|---|---| | T11.1 | комментарий: тест «q1 без m1» — регрессионный, на test зелёный | deferred | | T11.2 | тест «два обновления одной строки на замороженных данных» | fixed c859ca1 (= M-8) | | T13.1 | test_patch_cell_null_is_explicit зависит от созданного им состояния (откат сессией) | rejected | | T13.2 | длинные строки >120 | rejected (стиль) | | T15.1 | EditCell.jsx:223 `<textarea value={undefined}>` — dev-предупреждение React при первом вводе | deferred | | T15.2 | вложенный accessorKey с undefined — dev-предупреждение TanStack (в prod нет) | rejected (design) | | I-3 | удаление групповой строки слало row_deleted без row_id (getDataRowId вернул undefined после strip), сервер падал на data["data"]["row_id"] и рвал WebSocket | fixed c859ca1 | | M-7 | buildCellUpdatedMessage нормализует только value | rejected (INPUT-строки only; покрыто фиксом I-3) | | M-8 | нет теста глубоко вложенного отсутствующего блока | fixed c859ca1 | | M-9 | нет теста jsonb_strip_nulls на литерале против _strip_nulls | fixed c859ca1 | | M-10 | X-DB-Time-Ms в B включает стоимость jsonb_strip_nulls: доля Python в A и B не сопоставима напрямую | deferred (оговорка рядом с замерами) | | R-6 (design #6) | PATCH null: сначала 225, затем null | fixed (решение) | | R-7 (design #7) | getDataRowId возвращает null | fixed c859ca1 | | R-8 (design #8) | аудит Task 15 дополнен проверкой полезной нагрузки WebSocket | fixed (решение) | | O-6 | на origin/test cellUtils.js импортирует './rowUtils' без .js — красный шаг требовал временной правки; тест «q1 без m1» зелёный и на test | rejected | | O-7 | ошибки biome в файлах #223 (cellUtils.js, cellUtils.test.js:10,23, useWebSocket.js) и в старом тесте rowUtils.test.js:17-19 | rejected (не наши) | Отложенное (deferred): T11.1, T15.1, M-10; из A: T5.2, T6.2, T7.4, T7.6, M-2, O-3 (rf-rollup r.year). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aep added 9 commits 2026-10-28 21:18:58 +03:00
Копируются только строки на пути к затронутой, остальные сохраняют идентичность;
без изменений возвращается тот же data. Отсутствующие в row.data ключи теперь
вставляются (нужно для AURORA-1844/1848). Тесты с паритетом к прежней реализации.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Четыре теста updateCells: вставка отсутствующего блока и поля,
явная запись null, вставка отсутствующего скалярного ключа data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
row_json_select(strip_nulls) оборачивает data в jsonb_strip_nulls внутри json_build_object;
флаг пробрасывается через get_json/get_svod1_json/get_svod2_json, роутеры листа и сводов
включают его. Проекты, PATCH/POST/DELETE не затронуты.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
form4_ids вычисляет vsp_ids и project_ids из строк FORM_4 через .get
с пропуском отсутствующих ключей, grow_form4_sheet использует её.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
После jsonb_strip_nulls у групп/позиций нет ключа line_id, getDataRowId
возвращал undefined, и row_id в сообщении удаления сериализовался в {}
(KeyError на сервере). Возвращаем null, как до фазы B.
Добавлены тесты updateCells (глубокое отсутствие блока, два обновления в батче)
и сверка jsonb_strip_nulls с _strip_nulls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Author
Owner

PG 15.12 (dfip-pg15:55434): ветка c859ca1 + исправление AURORA-1922 (временный worktree), полный pytest: 3 failed (те же 3 известных на test), 250 passed, 4 skipped. jsonb_strip_nulls на PG 15.12 и 16.15 идентичен (проверка ревьюером на литерале с {}, null в массиве).

PG 15.12 (dfip-pg15:55434): ветка c859ca1 + исправление AURORA-1922 (временный worktree), полный pytest: 3 failed (те же 3 известных на test), 250 passed, 4 skipped. jsonb_strip_nulls на PG 15.12 и 16.15 идентичен (проверка ревьюером на литерале с {}, null в массиве).
This pull request can be merged automatically.
You are not authorized to merge this pull request.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/233-aurora-1848-sheet-json-no-pydantic-b:feat/233-aurora-1848-sheet-json-no-pydantic-b
git checkout feat/233-aurora-1848-sheet-json-no-pydantic-b
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RSHB/DFiP_Budget_planing#242
No description provided.