Номер стадии не означал зависимости: между стадиями 1–4 ни один проход не читает вывод другого, и очередь между ними была платой ни за что. А правило про замеры держалось на двух именах и рассыпалось бы в день, когда мерить начнёт третий проход. Рёбер три вида, и они разной природы: зависимость (гейт → опиниативные, все проходы → триаж), конфликт за ресурс (ненаправленный) и барьер стоимости. Стадии остаются единицей состава, порядок задаёт граф: уходит всё, у чего входящие рёбра закрыты. Сериализует ресурс, а не имена: пометка «держит машину» — gate, adversary, ops, triage; остальные читают и рассуждают. Проект вправе пометить свой проход, снять пометку с перечисленных — нет. Ранний выход заменён барьером стоимости и стоит там, где выход зарабатывал: перед reimpl и architecture, то есть только в deep. Отдельным абзацем — что ребро значит порядок и никогда не данные: графовый словарь провоцирует обратное прочтение, а проход, увидевший чужие находки, соглашается с ними. Исключение одно и оно же сток. Диаграммы — mermaid, прогнаны через mermaid-cli. Режим прогона теперь «по графу» / «линейно»; task-batch и task-pipeline подтянуты под общий словарь, adversary и ops знают о пометке из своих charter'ов. DECISIONS 15. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
372 lines
31 KiB
Markdown
372 lines
31 KiB
Markdown
---
|
||
name: task-pipeline
|
||
description: Автономно проводит одну задачу через полный цикл Spec Driven Development — от постановки до коммита (opsx explore→propose→ревью спек профилем design→apply→ревью кода→archive→коммит), с обязательными чекпоинтами ревью и докладом об исходе. Использовать, когда просят взять/сделать задачу или довести идею до реализации.
|
||
---
|
||
|
||
# Пайплайн задачи
|
||
|
||
Оркестратор **одной** задачи по Spec Driven Development: проводит её от
|
||
постановки до коммита максимально автономно. Механику не согласовываем — делаем.
|
||
|
||
Это тонкая обёртка над каноническими скиллами `opsx:explore` / `opsx:propose` /
|
||
`opsx:apply` / `opsx:archive` — вызывай их через Skill, не переизобретай их шаги.
|
||
Ревью — скилл `av-dev-pipeline:review-pipeline`, он же держит правило выбора
|
||
профиля.
|
||
|
||
## Предпосылки
|
||
|
||
- **OpenSpec и скиллы `opsx:*` — жёсткая предпосылка, а не опция.** На них стоят
|
||
шаги 2, 3, 6 и 8, проход `review-specs` и профиль `design` (они завязаны на
|
||
`openspec/changes/<id>/specs/*/spec.md` и на `openspec validate --strict`).
|
||
**Проект без OpenSpec этим пайплайном не ведётся** — подключай OpenSpec, а не
|
||
вырождай цикл: ветка деградации здесь не пишется, потому что непроверенная
|
||
ветка деградации хуже честного отказа.
|
||
- **Скиллы зовутся с пространством имён** — `av-dev-pipeline:review-pipeline`,
|
||
`av-dev-pm:docs`, `av-dev-pm:tasks`. Короткое имя может разрешиться в
|
||
устаревшую проектную копию, и это произойдёт молча.
|
||
- **Проектные копии этих скиллов и агентов удаляются при установке плагина**
|
||
(`.claude/skills/` — и голые имена `task-pipeline`, `review-pipeline`,
|
||
`task-batch`, и с префиксом проекта: `<проект>-task-pipeline`,
|
||
`<проект>-review-pipeline`;
|
||
`.claude/agents/<проект>-review-*.md`). Две копии одного скилла расходятся, и
|
||
побеждает та, что короче названа.
|
||
|
||
Перед стартом прочитай `CLAUDE.md` проекта и то, на что он ссылается, если ещё
|
||
не в контексте. Проектные факты, нужные ревью — инварианты, семантика гейта,
|
||
объёмы, модель угроз, прецеденты, — живут в **документах канона** `av-dev-pm`;
|
||
карта «что где» — `references/project-facts.md` конвейера ревью.
|
||
|
||
**Документов канона нет — проект к нему не приведён.** Скажи это строкой и
|
||
предложи скилл `av-dev-pm:canon`: одна операция на проект против поразрядной
|
||
деградации на каждой задаче. Работу при этом не останавливай.
|
||
|
||
## Границы: чем пайплайн не владеет
|
||
|
||
- **Беклогом, спринтом, целями и приоритетами.** Задача приходит извне. Пайплайн
|
||
её не выбирает, не приоритизирует, не заводит и не переоценивает; если в
|
||
проекте есть свой процесс управления задачами — он и решает, что брать.
|
||
- **Форматом задач.** Пайплайн **не правит индексы руками и не выдумывает путь
|
||
к скрипту учёта**: он зовёт Skill `av-dev-pm:tasks`, который этим владеет
|
||
(шаг 11). Закрытие как таковое — его работа, и это осознанное решение с
|
||
названной ценой: **приёмщик и исполнитель совпали**. Закрытие поэтому **не
|
||
окончательно** — человек на сессии возвращает задачу `reopen` с причиной, а
|
||
доклад по критериям приёмки становится единственным, по чему приёмка вообще
|
||
возможна. Плагина `av-dev-pm` в проекте нет — вызов не разрешится, и тогда
|
||
учёт остаётся владельцу, о чём говорится в докладе.
|
||
- **Заведением задач из урожая ревью.** Отложенные находки отдаются **списком**
|
||
(см. шаг 7); превращать их в задачи — работа того, кто ведёт задачи проекта.
|
||
- **Определением ценности.** «Нужна ли эта функциональность» — не вопрос
|
||
пайплайна ни на одном шаге.
|
||
|
||
Пайплайн владеет **своим** определением готовности (ниже) и **сообщает
|
||
наблюдаемый исход**. Что с исходом делать дальше — не его дело.
|
||
|
||
## Наблюдаемые исходы
|
||
|
||
Ровно три, и каждый обязан быть назван в докладе прямо:
|
||
|
||
- **сделана** — определение готовности выполнено целиком;
|
||
- **не доведена** — с причиной и с записанным вопросом; что именно сделано и до
|
||
какой границы, названо явно;
|
||
- **оказалась крупнее задачи** — распознаётся **до заведения change**, иначе его
|
||
придётся выбрасывать. Дальше — декомпозиция, и это не работа пайплайна.
|
||
|
||
## Определение готовности
|
||
|
||
Задача сделана, когда верно всё:
|
||
|
||
1. гейт проекта зелёный;
|
||
2. ревью проведено **по профилю**, состав прогона сверен с таблицей профилей
|
||
поимённо, непущенные проходы названы в границах покрытия;
|
||
3. change заархивирован, дельты влиты в актуальные спеки;
|
||
4. коммит сделан в текущую ветку;
|
||
5. **критерии приёмки, если проект их дал, выписаны поимённо, и по каждому назван
|
||
оракул и наблюдаемый исход** — «прогнал вот это, увидел вот то». Это **доклад,
|
||
а не сертификация: приёмка — не работа пайплайна.** Исполнитель, ставящий себе
|
||
галочку «принято», проверяет свою работу своим же взглядом — по границе это
|
||
может делать только декоррелированный приёмщик. Критерии приходят снаружи;
|
||
пайплайн их не сочиняет и не занижает. Расхождение «по каждому критерию исход
|
||
есть, а суть задачи не достигнута» — дефект критериев, и о нём сообщается, а
|
||
не молча дорабатывается.
|
||
|
||
Пункты 1–4 — своё. Пункт 5 — внешнее: пайплайн доводит его до наблюдаемого
|
||
исхода и передаёт дальше.
|
||
|
||
## Принцип автономности
|
||
|
||
**Умолчание — делать, а не спрашивать.** Задача доводится до коммита без участия
|
||
человека; предполагается, что так пройдёт большинство задач.
|
||
|
||
Наткнулся на вопрос, который решать не тебе, — **не останавливайся и не
|
||
спрашивай**. Запиши его и продолжай:
|
||
|
||
1. **Запиши вопрос там, где проект держит вопросы** (секция беклога, файл
|
||
задачи, трекер — это знает проект). Если проект не сказал, куда, — отдельной
|
||
секцией `Вопросы` в своём докладе, и это тоже исход. Тело отвечает на три
|
||
вещи: **что именно решить**, **какие есть варианты и цена каждого**, **что
|
||
стоит, пока решения нет**. Плюс твоя рекомендация — человек чаще соглашается,
|
||
чем выбирает заново, и готовое суждение экономит ему весь контекст.
|
||
2. **Переформулируй задачу на остаток** — то, что делается без этого решения.
|
||
Назови границу: докуда доводим сейчас.
|
||
3. Доведи остаток до конца и закоммить. Задача не «висит на вопросе», она сделана
|
||
в объявленных границах.
|
||
|
||
**Что остатком не является — правило живёт не здесь.** Канонический текст с обеими
|
||
оговорками — в плагине `av-dev-pm`, скилл `av-dev-pm:session`, раздел
|
||
`## Вопрос, блокер, необратимое`, подраздел «Отличать вопрос от застревания».
|
||
Правило принадлежит управлению задачами, потому что решает **сделана задача или
|
||
вышла**, — это исход планирования, а не исполнения. **Ссылайся, не
|
||
пересказывай:** копия, заведённая здесь, уже однажды разошлась с оригиналом и
|
||
потеряла из перечня самое необратимое — запись **наружу**.
|
||
|
||
Коротко, чтобы знать, когда идти читать: остаток проверяется двумя порогами —
|
||
**материализация нерешённого** (запись состояния, зависящего от неотвеченного
|
||
вопроса) и **пол по пользе** (из остатка пропала польза, названная в постановке).
|
||
Оба порога — стоп: первый поднимает решение до начала записи, второй даёт исход
|
||
«не доведена».
|
||
|
||
Плагин `av-dev-pm` не подключён — правило не отменяется, а становится
|
||
осторожнее: прежде чем записать зависящее от нерешённого куда бы то ни было —
|
||
в хранилище, в журнал, в витрину или наружу, — спрашивай человека.
|
||
|
||
Нет полезного остатка — задача заканчивается исходом «не доведена», вопрос
|
||
записан, ничего не коммитится наполовину.
|
||
|
||
### Когда всё-таки спрашивать
|
||
|
||
Узко и по другому основанию — не «сложное решение», а **необратимое действие**:
|
||
|
||
- деплой, выкладка наружу, смена публичного адреса или токенов;
|
||
- удаление или перезапись рабочих данных, включая подрезку архивов;
|
||
- всё, что уходит за пределы машины.
|
||
|
||
Здесь ошибка не откатывается коммитом, поэтому спрашиваем даже когда решение
|
||
кажется очевидным. Развилка в дизайне — вопрос в запись; необратимое действие —
|
||
вопрос человеку сейчас.
|
||
|
||
Стиль правок — заточка под проект и конвенции, right-size, без золочения.
|
||
|
||
## Шаги
|
||
|
||
### 1. Прочитать задачу
|
||
|
||
Задача задана извне (slug, файл, ссылка, описание) — прочитай её и связанные
|
||
спеки и черновики. Не задана — попроси у вызывающего; сам в беклог не лезь и
|
||
приоритеты не интерпретируй.
|
||
|
||
Если проект даёт задаче **критерии приёмки**, выпиши их сразу: на шаге 3 они
|
||
уезжают в `tasks.md` change. Файл задачи может быть удалён до коммита, а
|
||
критерии обязаны его пережить.
|
||
|
||
Оцени тривиальность (влияет на шаг 4):
|
||
|
||
- **тривиальная** — локальная правка без изменения поведения, спек и схемы,
|
||
решение очевидно. Explore и ревью спек пропускаются;
|
||
- **нетривиальная** — новое или изменённое поведение, дизайн-развилки, задеты
|
||
инварианты, схема или несколько capability. Полный цикл.
|
||
|
||
Здесь же — проверка на «крупнее задачи»: если видно, что одним заходом это не
|
||
мерджится, объявляй исход **до** заведения change.
|
||
|
||
### 2. (Опц.) Груммить идею — `opsx:explore`
|
||
|
||
Только для идей и мутных постановок. Вызови Skill `opsx:explore`. Развилку
|
||
грумминга не выноси на человека — запиши вопросом и груми остаток. Выход: ясная
|
||
постановка, готовая к propose. **В explore не пишем код.**
|
||
|
||
### 3. Завести change — `opsx:propose`
|
||
|
||
Вызови Skill `opsx:propose`. Получаем `proposal.md`, дизайн (для нетривиальных),
|
||
дельта-спеки (`ADDED`/`MODIFIED`/`REMOVED Requirements`), `tasks.md`. Каждое
|
||
`### Requirement` содержит `SHALL`/`MUST`; структурные заголовки английские,
|
||
сценарии `GIVEN/WHEN/THEN`. Прогони `openspec validate --strict <id>`.
|
||
|
||
Критерии приёмки задачи, если они были, копируются в `tasks.md` отдельным блоком.
|
||
|
||
### 4. (Нетривиальная) Ревью предложения — профиль `design`, ДО кода
|
||
|
||
Первый чекпоинт. Вызови Skill **`av-dev-pipeline:review-pipeline`** с профилем
|
||
`design` и ссылкой на change `<id>`. Он запустит `review-specs`
|
||
(режим «дизайн ДО кода»), `review-rubric` (фаза 1: приёмочные критерии для
|
||
задуманного узла) и `review-architecture` по предложению.
|
||
|
||
Смысл профиля: архитектурная находка на готовом коде стоит переписывания и
|
||
потому игнорируется — та же находка здесь стоит абзаца обсуждения. Рубрику из
|
||
`review-rubric` перенеси в `tasks.md` как приёмочные критерии; там же уже лежат
|
||
критерии от постановки, если они были.
|
||
|
||
### 5. Отработать замечания ревью предложения
|
||
|
||
- Мелочь и явные улучшения — правь сам в спеках и дизайне.
|
||
- Развилки (компромисс, scope, инвариант) — вопросом в запись, спеки урезаются на
|
||
остаток.
|
||
- После правок перепрогони `openspec validate --strict <id>`.
|
||
|
||
### 6. Написать код — `opsx:apply`
|
||
|
||
Вызови Skill `opsx:apply` для реализации `tasks.md`. Код — по конвенциям проекта
|
||
(каталог `docs/conventions/`). Меняешь схему — обнови её описание в
|
||
документации тем же change, если проект этого требует: гейт обычно это проверяет.
|
||
|
||
Прогони гейт и добейся зелёного — он же гейт следующего шага.
|
||
|
||
**Поведенческая верификация.** Если задача меняет реальное поведение (новый
|
||
эндпоинт, разбор входа, схема, форма ответа) — зелёных юнит-тестов мало. Подними
|
||
изменение вживую командой из раздела команд `CLAUDE.md` и прогони сценарий.
|
||
Пропусти только для чисто внутренних правок без наблюдаемого рантайма.
|
||
|
||
**Сервис не оставляем лежать.** Если запуск упал — почини или откати до конца
|
||
шага.
|
||
|
||
### 7. Ревью кода — Skill `av-dev-pipeline:review-pipeline`
|
||
|
||
Второй чекпоинт. Вызови Skill **`av-dev-pipeline:review-pipeline`**, дав ссылку
|
||
на change `<id>`, базу диффа, профиль **и режим запуска**.
|
||
|
||
**Правило выбора профиля живёт в скилле конвейера** (раздел «Профили»), проектные
|
||
триггеры — в `docs/review.md`, если записаны. Здесь оно не пересказывается: три
|
||
копии одного правила расходятся, и работать будет та, которую прочитали
|
||
последней. Помни ровно одно — **профиль выбирается по факту изменения, а не по
|
||
ощущению важности**, и посмотри таблицу перед вызовом.
|
||
|
||
**Режим по умолчанию — `по графу`, и обосновывать его не надо.** Конвейер сам
|
||
знает свои рёбра: гейт открывает опиниативные проходы, проходы с пометкой «держит
|
||
машину» идут цепочкой (иначе замеры портят друг друга и находка выглядит
|
||
доказанной), дорогие generative-проходы ждут барьера стоимости, триаж — сток.
|
||
Твоего участия это не требует.
|
||
|
||
Просить **`линейно`** нужно только по причине, и она называется строкой: так
|
||
сказал оператор; машина занята чем-то ещё (в том числе соседней задачей батча);
|
||
идёт разбор самого конвейера.
|
||
|
||
Скилл сам гоняет гейт, нужные проходы и обязательный триаж. Возвращает отчёт с
|
||
потолком 7 пунктов, разметкой `Действие: инлайн | развилка` и секцией границ
|
||
покрытия.
|
||
|
||
**Сверь состав прогона с таблицей профилей в скилле, прежде чем коммитить.**
|
||
Отчёт обязан называть запущенные проходы **поимённо и с исходом**; непущенный
|
||
идёт строкой «не запускался» в границы покрытия. Реестр короткий (4–8 проходов) —
|
||
сверка стоит одного взгляда. Почему это правило существует, объясняет раздел
|
||
«Профили» скилла конвейера; здесь — само требование.
|
||
|
||
Отработай так же, как шаг 5: помеченное `инлайн` чини сам и не логируй,
|
||
`развилка` — вопросом в запись (он уже сформулирован триажем, его остаётся
|
||
перенести). После правок — снова гейт.
|
||
|
||
**Урожай — списком, не задачами.** Отложенные находки (реальный `major` не для
|
||
этого мерджа, развилка, решённая «потом», пачка `nit`) собери в секцию доклада
|
||
`Урожай`: формулировка, оракул, провенанс. Задачи из него **заводит не пайплайн**
|
||
— у того, кто ведёт задачи проекта, своя нарезка, свой формат и свои правила
|
||
дублей. Твоя обязанность — не потерять и передать.
|
||
|
||
**Границы покрытия из отчёта не выбрасывай** — они уезжают в финальный доклад
|
||
сжатой строкой. Отчёт, из которого исчезло «что проверить было невозможно»,
|
||
превращается в ложное ощущение проверенности.
|
||
|
||
**Отчёт триажа сохрани вместе с change (`openspec/changes/<id>/review/`; шаг 8
|
||
унесёт его в `openspec/changes/archive/<id>/review/` вместе с change) — это
|
||
обязательно, а не «если удобно».** По нему потом видно, что было найдено и что из
|
||
этого осталось в урожае. И это единственный **независимый** артефакт о составе
|
||
прогона: под оркестратором `task-batch` именно по нему сверяют полноту ревью
|
||
ветки, а не по твоей прозе — она написана тем же, кто мог проход и пропустить.
|
||
|
||
### 8. Архивировать — `opsx:archive`
|
||
|
||
Вызови Skill `opsx:archive`: change уезжает в архив, дельты вливаются в
|
||
актуальные спеки.
|
||
|
||
### 9. Синк документации
|
||
|
||
Ревью выполненного — до этого шага. Затем **вызови Skill `av-dev-pm:docs`**: он
|
||
владеет содержимым документов канона и ведёт чек-лист синка. Плагина нет — шаг
|
||
всё равно делается, см. ниже.
|
||
|
||
**Правило одно и оно жёсткое: принуждённое отрицание.** Доклад обязан назвать
|
||
**каждый** документ канона — либо чем он обновлён, либо «не требуется, потому
|
||
что…». Нетронутые группируются одной строкой с общей причиной. Список триггеров
|
||
прозой уже проверен на живом проекте и дал 6 записей ADR на 43 изменения;
|
||
работает только обязательное отрицание.
|
||
|
||
**Список документов и их триггеров здесь не дублируется** — он в чек-листе
|
||
скилла `av-dev-pm:docs`, и копия уже однажды разошлась с оригиналом, потеряв два
|
||
триггера.
|
||
|
||
**Плагина `av-dev-pm` в проекте нет** — путь в его дерево не разрешится ниоткуда,
|
||
поэтому за списком иди в **свой** reference:
|
||
[references/project-facts.md](../review-pipeline/references/project-facts.md)
|
||
конвейера ревью перечисляет все документы канона с их предметом. Пройди по этому
|
||
перечню — каждый документ получает строку, отрицание остаётся обязательным.
|
||
Триггеры при этом ты знаешь хуже, и это называется в докладе строкой: «синк
|
||
сделан по перечню документов, без списка триггеров — плагина `av-dev-pm` нет».
|
||
Канона в проекте тоже нет — назови это исходом и предложи `av-dev-pm:canon`.
|
||
|
||
### 10. Коммит
|
||
|
||
Коммить **в текущую ветку** (`git rev-parse --abbrev-ref HEAD`), сам ветку не
|
||
создавай и не переключай, ничего не пушь. При ручном запуске HEAD обычно на
|
||
основной ветке — коммит идёт прямо в неё; под оркестратором `task-batch` HEAD на
|
||
ветке задачи в изолированном worktree, и делать дополнительно ничего не нужно.
|
||
|
||
Сообщение — по-русски, скиллом `av-dev-git:commit`, если он подключён (первая строка «что
|
||
сделано», тело списком 1–3 пункта, без трейлеров). Одна задача — один осмысленный
|
||
коммит.
|
||
|
||
### 11. Закрыть задачу — **после коммита, не раньше**
|
||
|
||
**Вызови Skill `av-dev-pm:tasks`** и попроси закрыть задачу как реализованную —
|
||
он владеет форматом и двигает строку из набора спринта сам. Путь к его скрипту не
|
||
выясняй и индексы руками не правь: мост между плагинами — вызов скилла, а не
|
||
путь.
|
||
|
||
**Порядок обязателен.** Закрытие удаляет файл задачи; сделанное до коммита оно
|
||
оставило бы задачу закрытой без единого следа работы, если шаг 10 упадёт.
|
||
|
||
**Закрытие тоже коммитится — вторым коммитом, тут же.** Удаление файла задачи и
|
||
правка индексов (их имена знает `av-dev-pm`, не ты) — это правки в рабочем
|
||
дереве, и оставить их незакоммиченными нельзя по трём причинам: `task-batch` следом делает `rebase`
|
||
и `worktree remove`, а те откажут на грязном дереве; закрытие, не доехавшее до
|
||
основной ветки, оставит задачу открытой молча; и опора «набор спринта под git
|
||
показывает, что и когда закрыто» без коммита — пустые слова. Сообщение короткое,
|
||
про учёт, а не про работу: `закрыта задача <slug>`. Это второй коммит осознанно:
|
||
правило «одна задача — один осмысленный коммит» про работу, а учёт — не работа.
|
||
|
||
Плагина в проекте нет — вызов не разрешится. Тогда **ничего не выдумывай**:
|
||
скажи в докладе, что учёт задач остаётся за владельцем, и назови исход.
|
||
|
||
**Приёмщик и исполнитель здесь совпадают**, и закрытие не окончательно: человек
|
||
на сессии может вернуть задачу (`reopen` с причиной). Поэтому доклад по критериям
|
||
приёмки — не формальность, а единственное, по чему приёмка вообще возможна.
|
||
|
||
Готово — доложи кратко.
|
||
|
||
- **исход** задачи одним из трёх слов и, если не «сделана», чем ограничен
|
||
результат;
|
||
- что сделано, какие вопросы записаны и куда;
|
||
- ссылка на архивный change и хеш коммита;
|
||
- по каждому критерию приёмки, если они были: **оракул и наблюдаемый исход** —
|
||
это доклад приёмщику, а не отметка «принято»;
|
||
- **`Урожай`** — отложенные находки списком (формулировка, оракул, провенанс).
|
||
Задачи из него заводит тот, кто ведёт задачи проекта;
|
||
- **одна строка границ покрытия**: какой профиль и режим гонялись, какие проходы
|
||
не запускались и что проверить было невозможно. Доклад без неё сообщает
|
||
«проверено», не сообщая, что именно.
|
||
|
||
## Тонкости
|
||
|
||
- **Не завязывайся на основную ветку и корень репозитория.** Скилл работает в
|
||
текущем worktree и на текущей ветке: не делай `git checkout`/`switch`, не
|
||
создавай веток, не пушь.
|
||
- Не пропускай `openspec validate --strict` перед архивацией.
|
||
- Тривиальная задача: шаги 2 и 4 пропускаются; ревью кода (шаг 7) остаётся
|
||
всегда, но в профиле `quick`.
|
||
- Гейт блокирует: пока он красный, опиниативные проходы не запускаются. Чинить и
|
||
перезапускать, а не «посмотреть заодно».
|
||
- Если ревью предлагает крупную переработку — это развилка: не правь молча и не
|
||
спрашивай, запиши вопросом и доведи остаток.
|
||
- Держи вызывающего в цикле короткими репликами на переходах фаз, но не проси
|
||
подтверждать механику.
|
||
- **Занизить профиль ревью или пропустить проход — самый дешёвый способ
|
||
«ускориться», и он же самый дорогой по последствиям.** Защита одна: профиль
|
||
выбирается по факту изменения, состав сверяется поимённо, а непущенное
|
||
называется в отчёте строкой.
|