Общее описание работы линий разбора приведено на вики ([ссылка](https://wiki.yandex-team.ru/maps/dev/core/wikimap/mapspro/wikinktasks_cur/#linijarazborainprogress)).

# Алгоритм подмены таски при отправке на UI для пользователей без доступа к 1-ой линии.

Если таска никогда не покидала 0-ой линии разбора, никакой подмены не происходит.
Единственное, что происходит с историей, часть операций, не отображается в UI. Так было всегда. Например, aquire, release, change-type, mark-view и unrecognized не отображаются.

Если же таска в ходе работы была переведена на 1-ю линию, мы не хотим показывать это пользователю без доступа к ней. Потому кроме обычного скрытия неUI-ных операций происходит подмена полей `taskState, resolved, processingLevel и history` и `validOperations`.

## Подмена task.processingLevel.
Для пользователей на 0-ой линии разбора всегда подменяем processingLevel таски на '0'. Нулевое значение на UI не посылается. Так что пользователь не будет видеть, что у таски есть како-то уровень, и что он нулевой.

## Подмена финального решения таски.

В поле resolved показываем (если есть) решение по таске.

Пользователям с 0-ой линии не показываем причину отклонения.

Если у таски есть финальное решение, и оно отличается от предложенного пользователем при переводе на 1-ю линию разбора, то показываем, что таска заресолвлена. Время и автор решения могут отличаться от фактического. При сравнении решений учитываем только вердикт, не обращая внимания на причину отклонения, дату и автора решения.

Если находится на 1-м уровне и открыта (ещё не была закрыта там или была переоткрыта после закрытия или после нид-инфо), то показываем, что таска заресолвлена пользователем так и тогда, как и когда этот пользователь перевёл её на 1-ю линию.

## Подмена валидных операций.

Если таска на 1-ой линии, хотим, чтобы пользователи без доступа к 1-ой линии не могли делать с таской ничего. То есть список валидных операций очищается.
Исключение - пользователь без доступа к 1-ой линии, имеющий право переоткрывать таски, может "переоткрыть" таску, которую он только что "закрыл" (на самом деле - перевёл на первую линию). 

Если после "закрытия" (а на самом деле - перевода на 1-ю линию), с ней на первой линии ещё никто ничего не делал, то для пользователя, предложившего решение (и только для него) добавляем к пустому списку единственную доступную доступную операцию - Open.

## Подмена истории.

Пусть есть пользователи user0 (без доступа к первой линии) и user1 и user2 с доступом.

Рассмотрим, как будет выглядеть подмена истории для user0 на примере таски, переведённой на 1-ый уровень с некоторой резолюцией:

История таски в базе:
1. create (by robot)
1. reveal (by robot)
1. acquire (by user1)
1. release (by user1)
1. accept (by user1)
1. open (by user1)
1. acquire (by user0)
1. processing-level-up (by user0 with suggested verdict = 'rejected')
1. release (by user0)

Вся эта история кроме последних пунктов происходит на 0-ой линии. Для пользователя без доступа к 1-ой линии история будет выглядеть так:

1. reveal (by robot)
1. accept (by user1)
1. open (by user1)
1. reject (by user0)

Часть правок была скрыта, так как операции вообще в UI не отображаем (например, create, reveal, acquire, release).

Финальная строчка показывает подмену processing-level-up соответствующей резолюцией.

### Вариант 1. Закрытие на 1-ой линии с резолюцией, отличающейся от предложенной.

При сравнении финальной резолюции (если есть) и предложенной при lvl-up'е не учитываем причину отклонения. То есть в отредактированной истории reject(spam) то же самое, что и reject(no-process).

Если в конце концов таску на 1-ой линии заресолвили **иначе**, чем предлагал user0, когда закрывал её (то есть, когда на самом деле сделал processing-level-up), то любому пользователю с 0-ой линии (не только user0) будет видна лишь **часть** операций с 1-ой линии: reject, accept и deploy.

#### Дедупликация элементов на 1-м уровне
При этом возможна дупликация элементов истории.
Например, если на 1-м уровне были такие элементы
1. processing-level-up (by user0 with suggested verdict 'accepted')
1. accept (by user1)
1. open (by user2)
1. reject (by user2 with reason 'spam')
1. open (by user1)
1. reject (by user1 with reason 'no-data')
1. deploy (by robot),

то пользователь на 0-м уровне может видеть
1. accept (by user0)
1. accept (by user1)
1. reject (by user2)
1. reject (by user1)
1. deploy (by robot).

Чтобы избежать такого, оставляем первый из последовательных повторяющихся элементов. При удалении таких дублей тоже считаем последовательные reject равными, даже если причины отклонения разные.

Значит, история для пользователей с 0-ой линии будет в таком случае:
1. accept (user0)
1. reject (user1)
1. deploy (robot)

#### Подмена автора и времени показываемого решения
Возможна ситуация, когда автор и время финального решения в таске подменяются.

Пусть последние элементы истории выглядят так:
1. processing-level-up (by user0 with suggested verdict 'accepted' at timestamp0)
1. reject (by user1 with reason 'no-data' at timestamp1)
1. open (by user2)
1. reject (by user2 with reason 'spam' at timestamp2)
1. deploy

Тогда фактическое финальное решение по таске:
`Rejected(spam) by user2 at timestamp2`.

Однако история для пользователя без доступа к 0-ой линии выглядит так:
1. accept (by user0 at timestamp0)
1. reject (by user1 at timestamp1)
1. deploy

Чтобы решение по таске, показываемое в таске, не отличалось от последней записи в истории, подменяем фактичекское решение на последнее, которое видит пользователь в истории.

Тогда отображаемое финальное решение по таске:
`Rejected by user1 at timestamp1`.


### Вариант 2. Закрытие на 1-ой линии с резолюцией, совпадающей с предложенной.

Если в конце концов таску на 1-ой линии заресолвили так, как и предлагал user0, когда закрывал её (то есть, когда на самом деле сделал processing-level-up), то любому пользователю с 0-ой линии (не только user0) не будет видна ни одна операция с 1-ой линии кроме deploy (если он есть).

В качестве финального решения в карточке таски будет отображаться закрытие, полученное из level-up'а. Автором этого отображаемого решения будет пользователь, переведший таску на 0-ой уровень, отображаемое время такого закрытия - время перевода на 1-ый уровень.

Например, пусть с этой таской ещё поработали на первой линии разбора, добавив к истории следующие элементы:

1. create (by robot)
1. reveal (by robot)
1. acquire (by user0)
1. processing-level-up (by user0 with suggested verdict = 'rejected' at timestamp0)
1. release (by user0)
1. acquire (by user1)
1. release (by user1)
1. reject (by user1)
1. open (by user2 also with processing_level_1 permission)
1. need-info (by user1)
1. open (by user1)
1. <some other crazy operations by users at 1-st processing level>
1. acquire (by user1)
1. reject (reason = spam) (by user1 at timestamp1)
1. deploy (by robot)

Тогда **полная** история таски для любого пользователя без доступа к 1-ой линии будет выглядеть так:

1. reveal (by robot)
1. reject (by user0 at timestamp0)
1. deploy (by robot)

Резолюция в карточке таски будет
`Rejected by user0 at timestamp0`.

## Подмена TaskState

Если для 0-ой линии показываем, что таска закрыта (Accepted или Rejected), то и TaskState показываем соответствующий: Accepted или Rejected.
Если для 0-ой линии таска открыта, показываем реальный TaskState таски.

## known issues.
### Мигает история при изменении решения по таске.

Пусть user0 сделал level-up (accept). Потом на 1-ой линии - reject(by user1). 

user0 заходит в историю и видит:
1. accept (by user0)
1. reject (by user1)

Потом на 1-ой же линии сделали последовательно open(by user1) и accept(by user1).

user0 заходит в историю и видит:
1. accept (by user0)
То есть `reject`, видимый ранее пропал, так как таска теперь закрыта с тем же вердиктом, что был предложен при переводе на 1-ю линию.

Потом на 1-ой же линии сделали последовательно open(by user1) и reject(by user1).
Пользователи на 0-ой линии снова видят элементы с 1-ой линии:
1. accept (by user0)
1. reject (by user1)
1. accept (by user1)
1. reject (by user1)
