using Ban.Sdaid.Notation.Documents;
using Ban.Sdaid.Notation.Glossary;
using Ban.Sdaid.Icd.Domain.Processing;
using Ban.Sdaid.Icd.Epics.CardInput;
using Ban.Sdaid.Icd.Epics.CardInput.UseCases;
using Ban.Sdaid.Icd.Epics.PacketProcessing;
using Ban.Sdaid.Icd.Epics.PacketProcessing.UseCases;
using Ban.Sdaid.Icd.Epics.PacketProcessing.UseCases.StateMachines;
using Ban.Sdaid.Icd.Glossary.Terms;
using Ban.Sdaid.Icd.Requirements;
using Ban.Sdaid.Icd.Arch.Adr;
using Ban.Sdaid.Icd.Epics.CardInput;
using Ban.Sdaid.Icd.Ui.Pages;
using Ban.Sdaid.Icd.Vision;
namespace Ban.Sdaid.Icd.ChangeRequests
{
/// <summary>
/// Запрос на изменение: отказ от плана ввода. Кадры снимаются подряд, вид документа и форма
/// определяются Сервисом, неверно распознанный вид отправляет пакет на повторную обработку.
/// </summary>
public class DOC_CR_2026_08_14_InputWithoutPlan : IChangeRequestDocument, IHasStructuralLinks
{
public static string _refName = "запрос на изменение «Ввод без плана»";
public string Name => "CR 2026-08-14. Ввод без плана ввода";
public string Description =>
@"Отказ от выбора плана ввода: пользователь снимает страницы подряд, вид документа и форму печатного бланка определяет Сервис, ошибку распознавания вида пользователь возвращает в очередь на повторную обработку.";
public string Version => "0.1";
public string Status => "draft";
public string[] Comments => new[]
{
"2026-08-14. Заведён до правок в артефактах: сначала фиксируем причину и объём.",
};
public SdaidLink[] Links => new[]
{
Rel.Uses<IcdVision>(),
Rel.Uses<FR_001_ImageInput>(),
Rel.Uses<FR_003_AttributeExtraction>(),
Rel.Uses<FR_008_FreePacketComposition>(),
Rel.Uses<FR_009_PacketQueue>(),
Rel.Uses<ADR_001_InputPlanDrivenByCardKind>(),
Rel.Uses<ADR_002_PacketIdentityAndFileKeys>(),
Rel.Uses<ADR_005_FieldValueSourceBinding>(),
Rel.Uses<ADR_006_CardDataStructure>(),
Rel.Uses<ADR_007_InputWithoutPlan>(),
Rel.Uses<ADR_008_PacketStatesAndTwoTabs>(),
Rel.Uses<EPIC_CardInput>(),
Rel.Uses<InputDataPage>(),
};
public static string S1_Source = """
## Суть изменения
Ввод перестаёт идти по заранее выбранному плану. Пользователь снимает или загружает
кадры страниц подряд; каждому новому кадру присваивается очередной номер страницы,
порядок правится перетаскиванием. Ввод карты завершается командой «Сохранить и перейти
к следующей»; сверху действует настраиваемый предел числа кадров в пакете, по умолчанию
пять.
Экран очереди упрощается следом: вместо пяти вкладок по этапам обработки остаются две —
«Пакет ввода» со списком кадров и «Проверка карты», где пользователь проверяет, правит
и принимает данные. Подсказка поиска — «№ пакета · шифр · инв. № · заглавие».
Вид документа и редакцию бланка определяет Сервис. Если при проверке вид оказался
распознан неверно, пользователь отклоняет его и может указать верный: пакет уходит
на повторную обработку с контекстом «такой-то вид отвергнут, верным считать такой-то»,
а пользователь берёт следующий пакет, не дожидаясь результата. Пакет, в котором не
опознан ни один вид, помечается как ошибочный.
""";
public static string S2_Analysis = $"""
## Разбор
### Что меняется по существу
Выбор плана ввода исчезает из работы пользователя. Вместо последовательности шагов, заданной
заранее, ввод сводится к съёмке страниц подряд; номер страницы присваивается по порядку
съёмки и правится перетаскиванием. Определение вида документа и редакции бланка
переносится с пользователя на Сервис.
Ошибка распознавания вида правится не редактированием значений, а возвратом на повторную
обработку: пользователь сообщает, что вид неверен, и **может указать правильный**. Тогда
контекст повторной обработки содержит обе части — какой вид отвергнут и какой считать
верным. Пользователь не ждёт результата, а берёт следующий пакет.
Если не опознан ни один вид, пакет помечается как ошибочный: обрабатывать нечего,
и дальше он идёт в ручной разбор, а не по кругу.
Полнота {GlossaryAnchors.RefTo<InputPacket>("пакета ввода")} определяется не Сервисом,
а пользователем: ввод завершается командой
«Сохранить и перейти к следующей». Сверху действует настраиваемое ограничение —
наибольшее число кадров в пакете, по умолчанию пять.
### Почему это ускоряет ввод
Из работы уходят два действия на каждую карту: выбор плана и следование его шагам.
При объёме архива около 50 тыс. карт это заметно. Дополнительно снимается ошибка,
которую план допускал: оператор мог выбрать план, не соответствующий бумаге, и заметить
это только на проверке.
### Чем платим
**Распознавание становится обязательным звеном ввода.** Раньше план гарантировал, что
Сервис знает, что за карта; теперь это гипотеза модели. Пакет с неопознанным видом
не может быть разобран в значения вообще, а не только частично.
**Появляется цикл повторной обработки с обратной связью.** Это новое поведение очереди:
пакет возвращается в неё с контекстом «вид такой-то отвергнут, верным считать такой-то».
От бесконечного хождения по кругу защищает не счётчик попыток, а то, что пользователь
вправе указать верный вид, а неопознанный вовсе пакет уходит в ошибку.
**Пользователь теряет подсказку.** План говорил, что снимать следующим; без него
полнота пакета определяется только распознанной формой, то есть постфактум.
### Что переживает переделку
Эти решения не связаны с планом и должны сохраниться: три источника изображения,
доступные одновременно; накопитель с правкой и удалением кадров до постановки в очередь;
список созданных пакетов с возвратом к любому; немедленный переход к следующей карте;
автоматическая постановка в очередь без отдельной кнопки.
""";
public static string S25_Queue = $"""
## Очередь обработки: две вкладки вместо пяти этапов
### Что должно остаться на вкладке «Пакет ввода»
Кроме того, что названо в запросе — пересъёмка, повторная обработка, отметка включения
кадра в обработку, — на этой вкладке живёт то, что было на прежних этапах
«Предобработка» и «Проверка файлов»:
| Что | Зачем |
|---|---|
| Полноэкранный просмотр с переключателем «оригинал / обработанное» | годность кадра видна только после нормализации; это и было смыслом проверки файлов |
| Удаление кадра и добавление недостающего | доснять страницу, пропущенную при вводе |
| Назначение кадра странице формы | Сервис распределяет кадры по страницам опознанной формы, пользователь переназначает; изменение требует повторной обработки |
| Состояние кадра: обработан, в обработке, ошибка нормализации | иначе непонятно, чего ждать и что переснимать |
| Признак «пакет изменён после обработки» | добавили или переснили кадр — результаты распознавания устарели; пересборка ручная, чтобы не затереть правки полей |
### Полнота пакета и полнота карты
Сервис определяет вид формы, а значит и число её страниц, и распределяет кадры
по страницам. Из этого следуют три случая.
**Кадров больше, чем страниц.** Лишние помечаются «не относится к форме», галочка
включения снимается — в обработку они не идут. Пользователь может удалить их,
но не обязан: удалить всегда успеется, восстановить снятое — нет.
**Кадров не хватает.** Сервис показывает, для каких страниц нет кадров. Пользователь
либо добавляет кадр, либо переснимает лишний нужной страницей — второе короче
и не упирается в предел пакета.
**Страница так и не снята.** Ничего не блокируется: Сервис просто не предзаполнит поля
этой страницы, пользователь заполняет их сам. Сервис — помощник в переносе бумаги
в цифру, а не сторож полноты.
Единственный контроль на выходе — **обязательные поля**: карта не создаётся, пока
они не заполнены. Обязательность задаётся составом вида документа и от того, сколько
кадров в пакете, не зависит.
### Поведение вкладок
**Пакет ввода.** Список кадров, опознанный вид карты и опознанные страницы. Действия
над кадрами: пересъёмка, повторная обработка, отметка включения кадра в обработку,
удаление, добавление недостающего, порядок страниц. Кнопка подтверждения переводит
на «Проверку карты». Кнопка **«Вид документа не распознан»** отклоняет вид с указанием
верного и отправляет пакет на повторную обработку.
**Проверка карты.** Показывает результат распознавания и даёт его править. Распознанные
значения при этом сохраняются и остаются доступны для показа: пользователь должен видеть,
что прочла модель, даже после того как исправил.
### Повторная обработка после правки кадров
Пакет с изменёнными кадрами возвращается в очередь **по кнопке «Поставить в очередь»**,
а не автоматически. Момент повторной обработки выбирает человек — иначе каждое движение
кадра запускало бы распознавание заново. После постановки Сервис предлагает сразу взять
следующий пакет.
**Новые результаты распознавания не затирают введённое пользователем.** Отсюда же
требование к хранению: у значения два набора — то, что видит и правит пользователь,
и то, что вернула модель.
### Состояния пакета
Вместо пяти этапов у пакета четыре состояния: **в очереди**, **проверка**, **завершён**,
**ошибка**. По ним же фильтруется очередь.
Каскадный отзыв подтверждений исчезает вместе с этапами и не требует замены: проверка
заканчивается созданием карты, после чего пакет не правится — обесценивать нечего.
### Что схлопывание вкладок меняет по существу
Пять этапов ({nameof(ADR_003_StageConfirmationModel)}) были не пятью экранами,
а моделью подтверждения: из последнего подтверждённого
этапа выводился статус пакета, на этапах строились фильтры очереди и каскадный отзыв.
Всё это заменяется четырьмя состояниями, поэтому переделка задевает не только экран.
Проверка карты становится единым действием: поля, экземпляр, экспертиза и вид документа
проверяются на одной вкладке, а результат — принятие карты либо отклонение вида
с отправкой на повторную обработку.
""";
public static string S3_BlastRadius = $"""
## Blast radius
### Отменяется целиком
| Артефакт | Что в нём |
|---|---|
| {nameof(ADR_001_InputPlanDrivenByCardKind)} | решение, ради которого вводился план; замещается новым ADR |
| {nameof(FR_008_FreePacketComposition)} | требование о ведении планов; переписано в «Свободное формирование пакета кадров» |
| Сценарий «Ввод ИК по плану» | сценарий пошагового ввода; заменён на {nameof(InputCardUseCase)} |
| План ввода, Операция ввода | сущности и одноимённые термины глоссария |
### Переделывается
| Артефакт | Что меняется |
|---|---|
| {nameof(IcdVision)}, 4.2.1 | ввод перестаёт идти по плану; появляется автоопределение вида и формы |
| {nameof(IcdVision)}, 4.2.3 | в проверку добавляется отказ «вид документа распознан неверно» |
| {nameof(EPIC_CardInput)} | тонкая нить без плана |
| {GlossaryAnchors.RefTo<InputPacket>("Пакет ввода")} | вместо ссылки на план — распознанные вид документа и форма |
| {GlossaryAnchors.RefTo<ImageFrame>("Кадр изображения")} | вместо роли кадра — номер страницы с возможностью переупорядочить |
| {nameof(InputDataPage)} и его прототип | степпер по плану заменяется лентой кадров с перетаскиванием |
| {nameof(ADR_006_CardDataStructure)}, вариант 5 | на схеме нарисован план ввода с операциями |
| {nameof(ADR_003_StageConfirmationModel)} | замещается решением о четырёх состояниях: {nameof(ADR_008_PacketStatesAndTwoTabs)} |
| Этапы обработки пакета | перечисление из пяти значений сокращается |
| {nameof(FR_005_Verification)} | последовательность этапов проверки |
| {nameof(ProcessingQueuePage)} и его прототип | пять вкладок заменяются двумя; подсказка поиска |
| {nameof(InputPacketStateMachine)} | состояния строились на подтверждении этапов |
| {nameof(EPIC_PacketProcessing)} | границы и критерии приёмки описывали пять этапов с подтверждением |
| {nameof(VerifyPacketUseCase)} | сценарий вёл пользователя по этапам с отзывом подтверждений |
| Термины «План ввода», «Операция ввода» | понятий больше нет в модели |
### Затрагивается косвенно
| Артефакт | Почему |
|---|---|
| {nameof(ADR_002_PacketIdentityAndFileKeys)} | в ключе файла сидит вид кадра — станет номер страницы |
| {nameof(ADR_005_FieldValueSourceBinding)} | привязка к виду кадра заменяется привязкой к странице формы |
| {nameof(FR_003_AttributeExtraction)} | извлечение идентификации из запасного пути становится основным |
| {nameof(FR_009_PacketQueue)} | появляется повторная обработка с контекстом отрицания вида |
""";
public static string S4_Plan = $"""
## План проработки
| № | Шаг | Что даёт |
|---|---|---|
| 1 | Прототип экрана ввода: лента кадров, автонумерация страниц, перетаскивание, завершение карты | закрывает вопрос, чем заменить подсказку плана |
| 2 | Прототип очереди: две вкладки, отклонение вида с указанием верного, ошибочный пакет в списке | показывает цикл возврата целиком |
| 3 | Закрыть открытые вопросы по итогам прототипов | предел кадров, кадры вне формы, судьба ошибочного пакета |
| 4 | {nameof(ADR_007_InputWithoutPlan)} с замещением {nameof(ADR_001_InputPlanDrivenByCardKind)} | фиксирует решение и его цену |
| 5 | Домен: пакет ввода, кадр изображения; удаление плана и операций | приводит модель в соответствие |
| 6 | Требования и видение: FR-008 отменить, FR-001, FR-003, FR-009 и разделы 4.2.1, 4.2.3 переписать | убирает противоречия в тексте |
| 7 | Эпик и use-case: заменить «Ввод карты по плану» | тонкая нить без плана |
| 8 | Итог в этом CR | статус по каждому пункту |
### Почему прототип первым
Из пяти неясностей четыре — про поведение экрана: чем заменить подсказку плана, что
показывать до того, как вид распознан, как выглядит отклонение вида, куда девается
ошибочный пакет. На прототипе это решается за вечер, в тексте — обсуждается неделю
и всё равно проверяется прототипом.
Обратный порядок — сначала ADR, потом макет — оправдан, когда решение диктует поведение.
Здесь наоборот: решение почти принято, а его цена выяснится только на экране.
### Что придётся трогать в прототипах
Экран ввода переписывается целиком: степпер по шагам плана заменяется лентой кадров.
Экран очереди — частично: на этапе проверки добавляется отклонение вида с выбором
верного, в список пакетов — состояние ошибки.
Старый прототип не копируем: он в истории репозитория, и этого достаточно.
""";
public static string S45_Prototype = $"""
## Прототип экрана ввода
Кадры снимаются подряд, номер страницы присваивается автоматически и правится
перетаскиванием. Кадр можно пометить как не относящийся к бланку — для снимка
инвентарного номера на экземпляре; нумерацию страниц такие кадры не занимают.
Выбора плана и блока идентификации нет.
{SdaidHtml.LinkTo<InputDataPage>("input-card.html", "Открыть в новой вкладке")}
{SdaidHtml.IframeOf<InputDataPage>("input-card.html", 720)}
Прежний вариант со степпером по плану удалён: он остаётся в истории репозитория.
## Прототип очереди
Две вкладки вместо пяти этапов, четыре состояния пакета, отклонение вида с указанием
верного, повторная обработка по кнопке «Поставить в очередь».
{SdaidHtml.LinkTo<ProcessingQueuePage>("queue.html", "Открыть в новой вкладке")}
{SdaidHtml.IframeOf<ProcessingQueuePage>("queue.html", 720)}
""";
public static string S5_Questions = """
## Вопросы, закрытые заказчиком
| Вопрос | Ответ |
|---|---|
| Чем ограничен цикл повторной обработки | Пользователь при отказе может указать верный вид — тогда повторная обработка идёт с подсказкой. Пакет, где не опознан ни один вид, помечается как ошибка |
| Что делать, если вид не опознан вовсе | Пометить пакет как ошибочный |
| Как определяется полнота пакета при вводе | Решает пользователь: ввод завершается командой «Сохранить и перейти к следующей». Сверху — настраиваемый предел числа кадров, по умолчанию пять |
| Что если страницы не хватает | Ничего не блокируется: поля этой страницы не предзаполняются, пользователь вносит их сам |
| Что считается полной картой | Карта, где заполнены обязательные поля; состав кадров на это не влияет |
| Нужен ли выбор вида как подсказка Сервису | Да, при отказе от распознанного вида |
| Какие состояния остаются у пакета | В очереди, проверка, завершён, ошибка; по ним же фильтруется очередь |
| Сохраняется ли каскадный отзыв подтверждений | Не требуется: проверка заканчивается созданием карты, дальше пакет не правится |
| Кто запускает повторную обработку после правки кадров | Пользователь, кнопкой «Поставить в очередь»; следом предлагается взять следующий пакет |
| Как называется вкладка с кадрами | «Пакет ввода» |
| Кадры, не относящиеся к странице формы | Отдельного вида кадра нет: снимаются только страницы карты. Кадр, который Сервис не отнёс к странице, считается лишним — не распознаётся и удаляется без повторной обработки |
| Что считает предел кадров | Размер пакета целиком: пять кадров, и все они — страницы формы. Ничего лишнего в пакете не ожидается |
| Попытка добавить кадр сверх предела | Кадр не добавляется, показывается сообщение «Достигнуто максимальное количество кадров пакета ввода» |
| Судьба ошибочного пакета | Остаётся в очереди с признаком ошибки; отдельного списка разбора нет |
| Предел при повторной обработке | Тот же: кадры заменяются, добавить сверх предела нельзя |
## Открытые вопросы
Открытых вопросов нет.
""";
public static string S6_Result = $"""
## Итог
### Сделано
| Пункт плана | Статус | Что получилось |
|---|---|---|
| Прототип экрана ввода | выполнено | лента кадров, автонумерация, перетаскивание, предел кадров, завершение одной командой |
| Прототип очереди | выполнено | две вкладки, четыре состояния, отклонение вида, повторная обработка по кнопке |
| Закрыть открытые вопросы | выполнено | все вопросы CR закрыты ответами заказчика |
| ADR с замещением ADR-001 | выполнено | {nameof(ADR_007_InputWithoutPlan)} |
| Домен | выполнено | пакет, кадр, отклонение вида; удалены план, операция ввода, роли изображения, этапы обработки |
| Требования и видение | выполнено | {nameof(FR_001_ImageInput)}, {nameof(FR_003_AttributeExtraction)}, {nameof(FR_005_Verification)}, {nameof(FR_009_PacketQueue)}; {nameof(FR_008_FreePacketComposition)} переписано; видение 4.2.1–4.2.3, 4.2.5 |
| Эпик и сценарий | выполнено | {nameof(EPIC_CardInput)} и {nameof(InputCardUseCase)}; {nameof(EPIC_PacketProcessing)} и {nameof(VerifyPacketUseCase)} |
| Итог | выполнено | этот раздел |
### Сверх плана
Работа вскрыла то, чего в blast radius не было.
**Понадобилось второе решение.** Схлопывание пяти этапов в две вкладки отменяло
{nameof(ADR_003_StageConfirmationModel)}, а отменить решение можно только другим решением —
появился {nameof(ADR_008_PacketStatesAndTwoTabs)}. В первоначальном разборе я этого
не увидел: считал схлопывание вкладок правкой экрана.
**Эпик обработки и сценарий проверки** остались на старой модели и нашлись только
проверкой на документы-сироты — их не было в blast radius.
**Ссылки в спеке рендерились именами классов.** Механизм отображаемых имён был заполнен
у трёх страниц из ста; проставлен двадцати семи артефактам, теперь упоминания читаются
по-русски по всей спеке.
### Что изменилось в объёме
Артефактов стало меньше: удалены сущности плана ввода и операции ввода, перечисления
видов операций, ролей изображения и этапов обработки, сущность этапа, два термина
глоссария, сценарий ввода по плану и старые прототипы. Добавлены два решения, сценарий
ввода, отклонение вида ИК и состояние пакета.
### Что осталось незакрытым
{nameof(FR_008_FreePacketComposition)} не удалено и не отменено, а переписано в «Свободное формирование
пакета кадров»: номер требования сохраняет след — планы рассматривались, от них отказались
осознанно, — а содержание описывает действующий порядок ввода. {nameof(ADR_001_InputPlanDrivenByCardKind)}
и {nameof(ADR_003_StageConfirmationModel)} остаются в спеке как замещённые — их
аргументация понадобится, если новый подход не оправдается.
Открытые вопросы, поднятые переделкой, живут в своих документах: предел кадров на вид ИК
и возврат к созданному пакету — в {nameof(EPIC_CardInput)}; порог уверенности определения
вида и число возвратов в очередь — в {nameof(EPIC_PacketProcessing)}.
""";
}
}