Перейти к основному содержимому

Cost per Jira-таска: видеть стоимость до конкретной карточки

· 10 мин. чтения
Artur Pan
CTO & Co-Founder at PanDev

В Q1 2026 мы инструментировали инженерную организацию, у которой в отчёте красиво стоял «$340K на проект X за квартал». Но если посмотреть в топ-5 тикетов внутри этого проекта, картина другая. PROJ-1245 рефакторинг auth: $4 820. PROJ-1281 баг с форматом даты: $3 140. Двухчасовой багфикс стоил больше половины архитектурного рефакторинга. Шесть инженеров трогали этот тикет три недели подряд, потому что у него не было хозяина.

Этот разговор невозможно вести с цифрой по проекту. С цифрой по конкретному тикету — можно. В этом весь аргумент поста — и причина, по которой большинство Engineering Intelligence тулов спорят про не тот слой.

{/* truncate */}

Почему стоимость на уровне проекта — это не та единица измерения

LinearB, Jellyfish, Code Climate Velocity и большинство Engineering Intelligence платформ считают стоимость одинаково: суммируют время инженеров в ведро проекта, умножают на loaded rate, показывают как квартальную цифру. Цифра реальная. И при этом бесполезная для разговора, который должен случиться на sprint review.

State of Teams 2024 от Atlassian показывает, что средний Jira-тикет проходит 6 переходов по статусам и через него прокатываются 3,4 разных человека до закрытия. Вот тут живут решения. Стоимость по проекту усредняет все эти переходы. К моменту, когда «$340K проект» появляется в отчёте CFO, конкретные тикеты, которые раздулись, уже отмыты в общей сумме.

DORA в 2023 Accelerate State of DevOps Report показывает, что cycle time — это leading indicator стоимости. Не потому что медленные тикеты дороже по часу, а потому что медленные тикеты накапливают context-switch налог на каждом владельце. Этот налог видно только если можно назвать тикет. Дашборд проекта прячет это by design.

В исследовании Engineering Effectiveness 2024 Forrester меньше 18% инженерных организаций могут сколько-нибудь точно ответить «сколько стоила вот эта фича». Доля тех, кто может ответить «сколько стоил вот этот тикет», — функционально ноль. Это и есть разрыв. Feature-level версию проблемы разобрали в cost-per-feature; здесь спускаемся ещё на один уровень агрегации ниже.

Механика: per-ticket cost — это просто JOIN, без магии

Per-ticket cost требует трёх вещей и не больше:

  1. IDE-телеметрия, которая знает, на какую таску ушла каждая минута кода (через имя ветки → ключ задачи)
  2. Loaded hourly rate на каждого инженера (см. loaded-hourly-rate-true-cost)
  3. Jira-issue_key (или ClickUp / Linear / Asana key) на каждом коммите, ветке, ворклоге

В PanDev Metrics слой хранения для этого — материализованное представление mv_activity_total_user_issue_daily. Оно джойнит editor-activity events с распарсенным Jira-ключом из активной ветки и агрегирует на уровне «пользователь × день»:

-- Схема (упрощённо)
CREATE MATERIALIZED VIEW mv_activity_total_user_issue_daily AS
SELECT
ae.user_id,
ae.day_date,
SUM(ae.active_seconds) AS total_seconds,
ae.issue_key,
ae.department_id
FROM activity_events ae
WHERE ae.issue_key IS NOT NULL
GROUP BY ae.user_id, ae.day_date, ae.issue_key, ae.department_id;

Для сегодняшних данных, по которым view ещё не пересчитался, есть live-функция f_mv_activity_total_user_issue_daily_today() — она возвращает ту же форму данных, считая на лету по сырым таблицам. Расчёт стоимости накладывается сверху:

SELECT
m.issue_key,
SUM(m.total_seconds / 3600.0 * r.loaded_hourly_rate) AS cost_usd,
COUNT(DISTINCT m.user_id) AS engineers,
SUM(m.total_seconds) / 3600.0 AS hours
FROM mv_activity_total_user_issue_daily m
JOIN engineer_rates r ON r.user_id = m.user_id
WHERE m.department_id = 17
AND m.day_date BETWEEN '2026-04-14' AND '2026-05-13'
GROUP BY m.issue_key
ORDER BY cost_usd DESC
LIMIT 10;

Тот же SQL-паттерн, что и для project-level cost, минус один уровень GROUP BY. В этом единственная механическая разница. Интерпретационная — гигантская.

Тот же SQL-паттерн мы разбирали в cost-per-feature-sql-formula — здесь меняется гранулярность, формула остаётся.

Как выглядит реальный топ-10

Распределение из реальной команды на 14 инженеров за Q1 2026, blended loaded rate $95/час, окно 30 дней:

РангIssue KeyТипПриоритетВладелецЧасыИнженерыСтоимость
1PROJ-1245РефакторингP2A. Petrov624$4 820
2PROJ-1281BugP1без владельца → 6 рук496$3 140
3PROJ-1303MigrationP2M. Chen383$2 950
4PROJ-1319BugP3I. Volkov302$2 320
5PROJ-1330HotfixP1S. Rasulov223$1 860
6PROJ-1352StoryP2T. Lee192$1 640
7PROJ-1366StoryP3A. Petrov171$1 420
8PROJ-1378BugP2M. Chen142$1 280
9PROJ-1391StoryP3D. Aliyeva131$1 110
10PROJ-1402BugP3I. Volkov111$980

Бар-чарт топ-10 самых дорогих тикетов за 30-дневное окно: PROJ-1245 на $4 820 во главе, ниспадающее распределение до PROJ-1402 на $980. Распределение крутое: ранг 1 примерно в 5 раз дороже ранга 10. Это типичное соотношение, не выброс.

Три вещи, которые видны на этом уровне и не видны на уровне проекта:

Налог за бесхозный баг. PROJ-1281 — баг с форматом даты, P1, оценили как «двухчасовой фикс». Стоил $3 140 и съел 49 часов на шести инженерах, потому что ни один не был владельцем. Каждый из шести тратил 30–90 минут на загрузку контекста, частичный фикс и передачу дальше. Баг в итоге закрылся. Шесть передач из рук в руки — вот настоящая история.

Рефакторинги — не главные злодеи. Инженеры любят показывать пальцем на рефакторинги: «вот куда уходят деньги». PROJ-1245 (рефакторинг) стоил $4 820 — но у него был владелец, четверо инженеров параллельно делали 62 фокусированных часа, и он закрылся чисто. Per-hour-of-attention это самый эффективный пункт во всём списке.

P3-баги дороже P2-историй. PROJ-1402 (P3-баг) стоил больше нескольких P3-историй вместе. Баги не уважают свои priority-лейблы — они расширяются под доступное время, особенно когда воспроизведение нестабильное.

Распределение хотфиксов: где средние врут

Топ-10 — заголовок. Распределение внутри одного типа тикета — структурный вывод. Тот же датасет, тип «hotfix», 50 экземпляров за те же 30 дней:

СтатистикаСтоимость хотфикса
Медиана$620
Среднее$1 140
p75$1 420
p90$2 640
p95$3 800
Max$5 210

Среднее в 1,8x больше медианы. Это и есть главная проблема, когда CFO показывают «средняя стоимость хотфикса». Медианный хотфикс — это 6-часовой фикс, закрылся чисто. p95-хотфикс — это многодневная экспедиция на четверых инженеров, породившая два фоллоу-ап тикета и потребовавшая war room. Это разные звери. Назвать их обоих «хотфиксами» и усреднить — получите цифру, которая не описывает ни тех, ни других.

Если CFO спрашивает «сколько нам стоили хотфиксы за квартал?», правильный ответ содержит минимум три значения: медиана, p95, и количество выше $2 000. Меньше — прячет длинный хвост, который и наносит реальный урон бюджету.

Какой разговор открывает per-ticket cost

Цифра по проекту приводит к «надо тратить меньше на проект X». Это стратегический разговор. Стратегические разговоры идут шесть недель и заканчиваются слайдом.

Цифра по тикету приводит к «PROJ-1281 стоил $3 140, и мы до сих пор не знаем, кто отвечает за форматирование дат». Это операционный разговор. Он идёт 15 минут на retro и фиксится сразу.

В PanDev Metrics это живёт как EmployeeTasksWidget на personal-finance дашборде. Для каждого инженера он показывает не общую стоимость, а самый дорогой единичный тикет, который этот инженер трогал в периоде. Мы выбрали такую метрику намеренно. Total cost награждает тех, кто залогировал больше всех часов. «Самый дорогой пройденный тикет» вытаскивает наружу карточки, на которых внимание застряло. Два инженера с одинаковым total cost могут иметь очень разные worst-offender тикеты — и именно колонка worst-offender запускает разговор о приоритизации.

Дополняющий вид — /dashboard/finances/task/:taskId. Это per-ticket dynamic: график стоимости одного тикета во времени с разбивкой по инженерам. PROJ-1281 на этом графике — шесть отчётливых вспышек, по три недели апарт, каждая — другой инженер, между ними нули. Это и есть картина «никто не владел». Каскад вспышек = тикет передавали из рук в руки. Один высокий столбик = один человек на нём сидел. Форма графика — это диагноз.

API, который кормит оба представления — POST /departments/{id}/finance/tasks. Возвращает страницу тикетов с cost, percentageOfTotal и percentageChange относительно предыдущего периода. Так что видно не только «дорогие тикеты», но и «тикеты, чья стоимость ускорилась неделя к неделе». Ускорение обычно полезнее как сигнал: тикет, удвоившийся в стоимости между спринтами, — это leading indicator того, что владение уплыло.

Если команда уже использует DORA, это укладывается в фреймворк прямо: высокий lead time на отдельной карточке — это пожарная сигнализация дорогой задачи. Подробнее в DORA metrics 2026.

Как реально использовать это на retrospective

Механика — скучная. Дисциплина использования — там, где команды отличаются. Рабочий паттерн:

  1. Выгрузите топ-5 тикетов по стоимости за закрытый спринт, не за открытый. У закрытых стабильные данные.
  2. Для каждого — был ли cost ожидаемым? Если 5-дневный рефакторинг стоил $4 800 — это и закладывали. Если «двухчасовой баг» стоил $3 140 — вот тут разговор.
  3. На каждый неожиданный задайте один точный вопрос: кто должен был быть владельцем и не был? Не «почему так получилось» — это даёт постмортем. «Кто должен был владеть» даёт имя и изменение процесса.
  4. Трекайте p95 одного типа через спринты. Если p95 хотфиксов растёт от $3 800 до $5 400 за квартал — у вас структурная проблема в triage хотфиксов. Если стабилен — у вас нормальный incident pipeline.
  5. Не разбирайте каждый тикет. Смысл per-ticket cost — вытащить 5%, которые сломали бюджет, а не микроменеджить остальные 95%, которые сработали. Оптимизация не того слоя — это тоже потери.

Честный лимит

Per-ticket cost требует надёжной связки Jira ↔ коммит. Если в команде нет конвенции имён веток типа feature/PROJ-1234-description или ключ задачи не попадает в коммит-сообщение — атрибуция падает на уровень проекта. У движка просто нет ключа для джойна. Команды на Linear, ClickUp или Asana ловят то же требование со своими форматами ключей (ENG-1234, CU-abc123, T1234).

В наших внедрениях соблюдение branch-naming — самый сильный предиктор того, насколько полезным окажется finance-модуль. Команды выше 90% получают чистый ticket-level cost. Команды ниже 70% видят кучу строк «(unattributed)» и тратят два месяца на починку конвенции, прежде чем дашборды начинают что-то стоить открывать. Никакой умный ML это не починит. Если данные не размечены в источнике, никакая агрегация ниже по потоку их не восстановит.

Второй честный лимит: per-ticket cost не учитывает время review и тестирования людей, которые не работали с веткой. Ревьюер, потративший 90 минут на PR, но не делавший checkout, в IDE-heartbeat модели даёт ноль секунд на тикет. Мы показываем эту дельту отдельно, как review-load метрики, но это известная неточность per-ticket стоимости — реальная стоимость тикета чуть выше, чем мы её посчитали.

Что сделать завтра утром

Если команда на Jira и соблюдает branch-naming, эту цифру можно посчитать SQL-запросом по worklog-данным — тот же JOIN, что выше. Если IDE-телеметрии для точного джойна нет, родной time-tracking Jira даст приближение, с поправкой: self-reported worklog обычно на 30–40% ниже IDE-telemetry времени на командах, где мы измеряли и то, и другое.

В любом варианте действие одно: назовите самый дорогой тикет из последнего спринта, откройте его историю, спросите — был ли у него владелец. Если ответ «вроде как да» — это $3 000, которые сэкономите в следующем квартале. Разговор короткий. Цифра достаточно мала, чтобы по ней действовать. Это и есть то, что покупает per-ticket view.

Project-level cost говорит, сколько вы потратили. Per-ticket cost говорит, какие решения принять иначе в следующем спринте. Это разные продукты — и большинство engineering-finance тулов производят только первый.

Готовы увидеть метрики своей команды?

30-минутная персональная демонстрация. Покажем как PanDev Metrics решает задачи именно вашей команды.

Забронировать демо