Обе задачи влиты в test 01.11 (PR #239/#242, #244/#274), архив пропущен. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
14 KiB
sheet-cell-edit Specification
Purpose
Ответ сервера на правку ячеек листа бюджетной формы (HTTP PATCH /form/{id}/sheet/{sheet}/cell(s) и WebSocket cell_updated): какие строки в нём приходят, какими они должны быть относительно полного GET листа и сколько времени правка может стоить на сервере.
Requirements
Requirement: Ответ на правку содержит затронутые строки целиком
Ответ на правку ячеек листов AHR/CAP/OPER форм FORM_1, FORM_2 и FORM_4 SHALL содержать каждую изменённую строку INPUT и все её строки-агрегаты, то есть всех предков по дереву статей до ROOT включительно. Для FORM_4 предками считаются только ROOT раздела, GROUP программы и ITEM проекта изменённой строки. Агрегат SHALL входить в ответ, даже если его значения не изменились. Ответ SHALL NOT содержать строку META и строки других ветвей дерева. Поле data каждой строки SHALL быть полной строкой в том же виде, что и в GET листа с теми же direction и sections: пустые значения передаются явным null. Если задан sections, ключи верхнего уровня у исключённых разделов SHALL отсутствовать в data.
Scenario: Правка числовой ячейки возвращает строку и её предков
- WHEN исполнитель меняет
plan.q1у строки листа FORM_2/AHR - THEN ответ содержит эту строку INPUT и по одной строке-агрегату на каждый уровень её пути в дереве статей
- AND
dataкаждой строки ответа равноdataстроки того жеsort_orderиз последующего GET листа
Scenario: Правка нечисловой ячейки всё равно возвращает предков
- WHEN исполнитель меняет
header.justificationу строки FORM_2/AHR - THEN ответ содержит строку INPUT и всех её предков, хотя их суммы не изменились
Scenario: Очистка значения
- WHEN исполнитель записывает
nullвplan.q1 - THEN в строке INPUT ответа ключ
plan.q1присутствует со значениемnull(или 0 — так же, как в GET) - AND суммы предков в ответе уменьшены на прежнее значение ячейки
Scenario: Правка с фильтром разделов
- WHEN правка выполняется с
sections=plan - THEN ни одна строка ответа не содержит ключей разделов, отличных от
plan, а также служебных ключей, которых нет в GET с тем жеsections
Requirement: sort_order в ответе совпадает с полным листом
Значения row_type, depth и sort_order каждой строки ответа на правку SHALL совпадать со значениями этой же строки в полном GET листа с теми же параметрами, выполненном сразу после правки. sort_order — сквозной номер строки во всём листе, а не номер внутри ответа. Это SHALL выполняться для первой и последней строки листа, после добавления и удаления строк в листе, а также при совпадении ключа сортировки у строки INPUT и узла дерева. Порядок строк в GET при совпадении ключа SHALL быть детерминированным и одинаковым в GET и в ответе на правку.
Scenario: Первая и последняя строка листа
- WHEN правится первая по порядку строка INPUT листа, а затем последняя
- THEN у каждой строки обоих ответов есть строка с тем же
(row_type, depth, sort_order)в GET листа, и еёdataсовпадает
Scenario: После добавления и удаления строк
- WHEN в лист добавлены строки (POST line), одна из строк в середине листа удалена (DELETE line), после чего правится строка, расположенная ниже удалённой
- THEN
sort_orderкаждой строки ответа равен еёsort_orderв GET листа после этих операций
Scenario: Пакет правок по разным ветвям дерева
- WHEN через
PATCH /cellsодним запросом правятся строки двух разных ветвей дерева статей - THEN ответ содержит обе строки INPUT и объединение их предков без дублей, и каждая строка совпадает со строкой GET того же
sort_order
Scenario: Направление FORM_1
- WHEN правится строка FORM_1/AHR с
direction=Support - THEN
sort_orderстрок ответа равенsort_orderв GET FORM_1/AHR сdirection=Support
Requirement: Состав ответа на листах сателлитов, AHR_LIMIT и OTCH9F
На листах FORM_2 AHR_RENT, AHR_UTILITY и AHR_SECURITY ответ на правку SHALL содержать только изменённые строки. На AHR_LIMIT ответ SHALL содержать изменённые строки LEAF шаблона и их предков по шаблону (GROUP и SECTION). На OTCH9F ответ SHALL содержать все строки (все месяцы) того же сочетания статьи и оборудования, что и изменённая строка: остатки на начало месяца зависят от предыдущих месяцев. Для всех этих листов SHALL выполняться требование о совпадении data и sort_order с полным GET.
Scenario: Правка строки аренды
- WHEN исполнитель меняет
plan.q1у строки AHR_RENT - THEN ответ содержит ровно одну строку с
data.idэтой строки, и она совпадает со строкой GET AHR_RENT того жеsort_order
Scenario: Правка количества в лимитах
- WHEN исполнитель меняет
qty_q1у строки LEAF листа AHR_LIMIT - THEN ответ содержит эту строку и строки её группы и раздела с пересчитанными
amount_q1, и они совпадают с GET AHR_LIMIT
Scenario: Правка месяца в OTCH9F
- WHEN исполнитель меняет поступление за месяц у строки OTCH9F
- THEN ответ содержит строки всех месяцев того же оборудования той же статьи с пересчитанными остатками, и они совпадают с GET OTCH9F
Requirement: Обновление АХР после правки сателлита
После правки или добавления строки на AHR_RENT, AHR_UTILITY, AHR_SECURITY или AHR_LIMIT формы FORM_2 сервер SHALL отправить подключённым к листу AHR событие (cell_updated или row_added). Событие SHALL содержать синхронизированные строки AHR и всех их предков, включая уровень SUB_SUB_ITEM. Каждая из этих строк SHALL совпадать со строкой того же sort_order полного GET листа AHR. Если синхронизированных строк нет, событие SHALL NOT содержать строк AHR, то есть ответ пуст, а не весь лист. Строки AHR_LIMIT SHALL сопоставляться и со статьями AHR глубины 4 по num_group_id (поведение миграции 0037).
Scenario: Правка аренды обновляет АХР
- WHEN исполнитель меняет
plan.q1у строки AHR_RENT, связанной со строкой AHR - THEN строки, которые сервер готовит для события на лист AHR, совпадают со строками GET AHR того же
sort_order, и среди них есть синхронизированная строка INPUT с новой суммой
Scenario: Источник без синхронизированных строк
- WHEN запрашивается обновление АХР для строки сателлита, у которой нет связанной строки AHR
- THEN набор строк для события пуст
Scenario: Лимит на статье глубины 4
- WHEN правится строка AHR_LIMIT, код статьи которой совпадает с
num_group_idстатьи AHR глубины 4 - THEN набор строк для события содержит синхронизированную строку AHR этой статьи
Requirement: Пакет правок атомарен
Если хотя бы одна правка в пакете отклонена (неизвестная колонка, чужая строка, нет прав, окно закрыто), SHALL NOT применяться ни одна правка пакета, и ответ SHALL быть ошибкой.
Scenario: Ошибочная колонка в пакете
- WHEN
PATCH /cellsсодержит одну корректную правку и одну с несуществующей колонкой - THEN ответ — ошибка 4xx, и GET листа после запроса совпадает с GET до него
Requirement: GET листа не меняется
Содержимое GET листов FORM_1 и FORM_2 (строки, data, sort_order) после изменения SHALL совпадать с содержимым до него на тех же данных. Исключение — порядок строк с совпадающим ключом сортировки: до изменения он не был определён. Время GET FORM_2/AHR SHALL NOT вырасти больше чем на 10 %.
Scenario: Снимок GET до и после миграции
- WHEN на стенде профилирования снят GET всех листов FORM_1 и FORM_2 из манифеста до применения миграции и после неё
- THEN ответы попарно совпадают
Scenario: Время GET после смешанной нагрузки
- WHEN в одном соединении с БД чередуются правки ячеек и GET листа FORM_2/AHR
- THEN среднее время GET не больше базового + 10 %
Requirement: Время правки ячейки на FORM_1 и FORM_2
Правка одной ячейки листа FORM_1 или FORM_2 SHALL NOT собирать лист целиком: на правку SHALL приходиться 0 вложенных полных сборок листа. Среднее серверное время v3.upd_form_cell на FORM_2/AHR SHALL быть не больше 50 мс как на листе в 1154 строки, так и на листе в 2092 строки. Требование не распространяется на FORM_4 до слияния AURORA-1846.
Scenario: Соавтор на листе масштаба 1
- WHEN на стенде профилирования (масштаб 1, без grow, FORM_2/AHR 1154 строки) выполняется шаг
coauthor - THEN в
sql/coauthor/sql_top.jsonmean_exec_timeвызоваv3.upd_form_cell≤ 50 мс - AND вызовов
v3.v_form_viewне верхнего уровня (toplevel = false) нет, а число вызововv3.v_form2_view(p_form_id, p_sheet, p_sections)равно числу GET листа и не зависит от числа правок
Scenario: Соавтор на выросшем листе
- WHEN после
perfkit.gen.grow(FORM_2/AHR 2092 строки) шагcoauthorвыполняется повторно - THEN
mean_exec_timeвызоваv3.upd_form_cell≤ 50 мс
Requirement: Ручной ввод без очереди
Сервер SHALL успевать подтверждать правки одного соединения с частотой ручного ввода (5 правок/с), не накапливая очередь.
Scenario: Соавтор с частотой 5 правок в секунду
- WHEN бот соавтора на FORM_2/AHR отправляет 5 правок/с в течение шага
coauthor - THEN число полученных ответов (эхо и ошибки) составляет не меньше 95 % от числа отправленных правок