@aqa-pulse/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +43 -0
  2. package/bin/aqa-pulse.js +49 -0
  3. package/dist/backend/generate-source-facts.d.ts +2 -0
  4. package/dist/backend/generate-source-facts.js +607 -0
  5. package/dist/backend/merge-reports.d.ts +19 -0
  6. package/dist/backend/merge-reports.js +314 -0
  7. package/dist/backend/upload-report-artifacts.d.ts +9 -0
  8. package/dist/backend/upload-report-artifacts.js +772 -0
  9. package/dist/backend/upload-report.d.ts +13 -0
  10. package/dist/backend/upload-report.js +338 -0
  11. package/dist/dashboard-utils.d.ts +437 -0
  12. package/dist/dashboard-utils.js +2627 -0
  13. package/dist/history-utils.d.ts +72 -0
  14. package/dist/history-utils.js +267 -0
  15. package/dist/shared/business-assumptions.d.ts +14 -0
  16. package/dist/shared/business-assumptions.js +61 -0
  17. package/dist/shared/dashboard-helpers.d.ts +63 -0
  18. package/dist/shared/dashboard-helpers.js +429 -0
  19. package/dist/shared/dashboard-metric-info.d.ts +61 -0
  20. package/dist/shared/dashboard-metric-info.js +15 -0
  21. package/dist/shared/error-utils.d.ts +1 -0
  22. package/dist/shared/error-utils.js +6 -0
  23. package/dist/shared/formatting.d.ts +3 -0
  24. package/dist/shared/formatting.js +42 -0
  25. package/dist/shared/i18n/ru.d.ts +558 -0
  26. package/dist/shared/i18n/ru.js +577 -0
  27. package/dist/shared/metric-info.d.ts +5 -0
  28. package/dist/shared/metric-info.js +210 -0
  29. package/dist/shared/navigation.d.ts +31 -0
  30. package/dist/shared/navigation.js +99 -0
  31. package/dist/shared/test-history-helpers.d.ts +51 -0
  32. package/dist/shared/test-history-helpers.js +294 -0
  33. package/dist/shared/test-history-metric-info.d.ts +17 -0
  34. package/dist/shared/test-history-metric-info.js +20 -0
  35. package/dist/shared/text-utils.d.ts +2 -0
  36. package/dist/shared/text-utils.js +15 -0
  37. package/package.json +37 -0
@@ -0,0 +1,577 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ru = void 0;
4
+ exports.ru = {
5
+ dashboard: {
6
+ title: 'AQA Pulse — Unified Quality Assurance Platform',
7
+ badge: 'Observability Playwright',
8
+ sourceHint: 'Источник:',
9
+ generatedAt: 'Отчёт построен',
10
+ runTime: 'Время прогона',
11
+ projects: 'Проекты',
12
+ branchMeta: 'ветка',
13
+ commitMeta: 'коммит',
14
+ authorMeta: 'автор',
15
+ notice: {
16
+ doneTitle: 'Что уже реализовано:',
17
+ doneText: 'JSON-парсинг одного прогона, KPI, кластеры ошибок, список проблемных тестов и базовая визуализация.',
18
+ nextTitle: 'Что остаётся на следующие недели:',
19
+ nextText: 'история прогонов, API-слой и тренды по нескольким запускам.',
20
+ },
21
+ filters: {
22
+ title: 'Фильтры дашборда',
23
+ description: 'Фильтрация работает через query-параметры и сразу влияет на сводку, историю и ссылки детализации.',
24
+ branch: 'Ветка',
25
+ project: 'Проект',
26
+ file: 'Spec-файл',
27
+ apply: 'Применить',
28
+ reset: 'Сбросить',
29
+ all: 'Все',
30
+ },
31
+ tabs: {
32
+ overview: 'Обзор',
33
+ performance: 'Производительность',
34
+ flaky: 'Flaky-аналитика',
35
+ codeQuality: 'Качество кода тестов',
36
+ business: 'Бизнес-метрики',
37
+ team: 'Командные метрики',
38
+ ai: 'ИИ / ML',
39
+ ariaLabel: 'Категории метрик',
40
+ },
41
+ metrics: {
42
+ passRate: 'Доля успешных тестов',
43
+ failedTests: 'Упавшие тесты',
44
+ flakyTests: 'Flaky в текущем прогоне',
45
+ runDuration: 'Длительность прогона',
46
+ errorClusters: 'Кластеры ошибок',
47
+ environment: 'Окружение',
48
+ latestVsPrevious: 'Последний и предыдущий запуск',
49
+ failures: 'Падения',
50
+ flakyShort: 'Нестабильные',
51
+ duration: 'Длительность',
52
+ passRateTrend: 'Тренд доли успешных тестов',
53
+ statusDistribution: 'Распределение статусов текущего прогона',
54
+ recentRuns: 'История запусков',
55
+ notes: 'Замечания по AQA Pulse',
56
+ latestRuns: 'Последние прогоны',
57
+ durationTrend: 'Тренд длительности',
58
+ p95Duration: 'P95 длительности',
59
+ p99Duration: 'P99 длительности',
60
+ topSlowestTests: 'Топ медленных тестов',
61
+ topSlowestTestsP1: 'Топ медленных тестов (P1)',
62
+ phaseBreakdown: 'Разбивка по фазам',
63
+ suiteDuration: 'Длительность по наборам',
64
+ durationPerBrowser: 'Runtime-проекты / браузеры',
65
+ leadingPhase: 'Доминирующая фаза',
66
+ flakyTrend: 'Тренд нестабильности',
67
+ clusterDistribution: 'Распределение ошибок по кластерам',
68
+ problemHotspots: 'Проблемные сценарии',
69
+ brittlenessProxy: 'Прокси хрупкости',
70
+ failureConcentration: 'Концентрация падений',
71
+ retryDensity: 'Плотность повторов',
72
+ testSmellScore: 'Test Smell Score',
73
+ pomCompliance: 'POM Compliance',
74
+ assertionDensity: 'Assertion Density',
75
+ waitStrategyScore: 'Wait Strategy Score',
76
+ stepGranularity: 'Test Step Granularity',
77
+ isolationScore: 'Test Isolation Score',
78
+ selectorStability: 'Selector Stability Index',
79
+ sourceCoverage: 'Source Coverage',
80
+ problematicTests: 'Топ проблемных тестов',
81
+ topFlakyTests: 'Топ flaky-тестов по истории (P1)',
82
+ flakyScore: 'Индекс нестабильности',
83
+ unstableRuns: 'Нестабильные прогоны',
84
+ lastStatus: 'Последний статус',
85
+ timeToDetect: 'Time to Detect',
86
+ timeToFixFlaky: 'Time to Fix (Flaky)',
87
+ ciWasteTime: 'Потери времени CI',
88
+ costSection: 'Стоимостной сценарий',
89
+ costOfFlakiness: 'Стоимость нестабильности',
90
+ investigationCost: 'Стоимость разбора',
91
+ developerFriction: 'Индекс трения flaky',
92
+ releaseConfidenceScore: 'Прокси риска релиза',
93
+ automationRoi: 'Automation ROI',
94
+ costStructure: 'Структура стоимости',
95
+ configAssumptions: 'Параметры расчёта',
96
+ codeQuality: 'Качество кода тестов',
97
+ team: 'Командные метрики',
98
+ ai: 'ИИ / ML-метрики',
99
+ },
100
+ tooltips: {
101
+ passRate: 'Доля тестов, завершившихся статусом passed в текущем прогоне.',
102
+ failedTests: 'Количество тестов с финальным неуспешным статусом: failed, timed out или interrupted.',
103
+ flakyTests: 'Количество flaky-тестов именно в текущем прогоне: тест требовал ретраев или менял статус между попытками.',
104
+ runDuration: 'Общая длительность текущего прогона по данным Playwright.',
105
+ medianDuration: 'Медианная длительность одного теста в текущем прогоне.',
106
+ errorClusters: 'Группы одинаковых или похожих сообщений об ошибках для быстрого анализа.',
107
+ environment: 'Окружение запуска: ОС, версии Playwright и Node.js.',
108
+ latestVsPrevious: 'Сравнение текущего прогона с предыдущим доступным прогоном в истории.',
109
+ passRateTrend: 'История изменения доли успешных тестов по архивным прогонам.',
110
+ statusDistribution: 'Распределение финальных статусов тестов в текущем прогоне.',
111
+ recentRuns: 'Последние архивные прогоны, попавшие в историю AQA Pulse.',
112
+ notes: 'Служебные заметки и выводы, сформированные во время построения отчёта.',
113
+ durationTrend: 'Тренд общей длительности прогонов по истории.',
114
+ p95Duration: '95-й перцентиль длительности тестов в текущем срезе. Помогает видеть типичную верхнюю границу без влияния единичных экстремумов.',
115
+ p99Duration: '99-й перцентиль длительности тестов. Показывает хвост самых тяжёлых тестов и помогает искать редкие, но дорогие задержки.',
116
+ topSlowestTests: 'Самые медленные тесты текущего среза, требующие оптимизации.',
117
+ phaseBreakdown: 'Оценка распределения времени между подготовкой, исполнением тестовых шагов и завершением. Фазы определяются по шагам и служебным названиям в отчёте Playwright, а доли нормализуются по сумме фазового времени.',
118
+ suiteDuration: 'Какие наборы тестов суммарно занимают больше всего времени в текущем срезе. Наборы группируются по префиксу title или по имени spec-файла, а доли считаются внутри общего времени всех наборов.',
119
+ durationPerBrowser: 'Сколько времени занимают браузеры текущего среза. Если в отчёте есть поле browser, AQA Pulse использует его как есть. Если поля нет, по умолчанию используется Chrome. Доли считаются внутри общего времени по всем браузерам/проектам.',
120
+ flakyTrend: 'Тренд количества нестабильных тестов по архивным прогонам.',
121
+ clusterList: 'Распределение падений по кластерам ошибок и примеры тестов.',
122
+ problemHotspots: 'Количество сценариев, которые прямо сейчас формируют основной backlog по качеству тестового кода и требуют первоочередного разбора.',
123
+ brittlenessProxy: 'Прокси-хрупкость тестового набора: опирается на средний исторический flaky score и показывает, насколько часто набор ведёт себя нестабильно по истории.',
124
+ failureConcentration: 'Показывает, какая доля текущих неуспешных тестов сосредоточена в небольшом наборе проблемных сценариев. Чем выше доля, тем сильнее сигнал локализован в нескольких тестах.',
125
+ retryDensity: 'Плотность лишних повторов по истории: сколько rerun-нагрузки приходится на 100 наблюдавшихся запусков.',
126
+ testSmellScore: 'Композитный score по source-анализу Playwright spec-файлов. Учитывает жёсткие паузы, direct locator usage, отсутствие POM-сигнала, слабую step-структуру и хрупкие селекторы.',
127
+ pomCompliance: 'Доля тестов, где spec-файл выглядит как consumer page object / screen-model слоя, а не хранит основную locator-логику прямо внутри теста.',
128
+ assertionDensity: 'Среднее число expect() на тест по доступным исходникам. Помогает увидеть сценарии, которые делают много действий, но слабо проверяют результат.',
129
+ waitStrategyScore: 'Баланс между web-first/assert-based ожиданиями и жёсткими ожиданиями вроде waitForTimeout. Чем выше score, тем устойчивее стратегия ожиданий.',
130
+ stepGranularity: 'Среднее число test.step на тест. Метрика показывает, насколько сценарии разбиты на читаемые этапы для отчётов и диагностики.',
131
+ isolationScore: 'Эвристика независимости тестов по исходникам: penalizes shared mutable state, heavy beforeAll и serial execution hints.',
132
+ selectorStability: 'Оценка устойчивости selector-подхода: role/label/testid дают лучший score, длинные CSS-цепочки и XPath — худший.',
133
+ sourceCoverage: 'Какая доля тестов текущего среза была реально сопоставлена с доступными spec-файлами и попала под source-анализ.',
134
+ problematicTests: 'Тесты с наибольшей долей падений и высокой вероятностью повторных инцидентов.',
135
+ failureRate: 'Доля неуспешных попыток от общего числа запусков теста.',
136
+ topFlakyTests: 'Приоритетный список для разбора по архивной истории AQA Pulse: приоритизация строится по flaky-индексу, а не только по текущему запуску. В таблице показывается топ-10 тестов, а расчёт опирается на последние 20 архивных прогонов.',
137
+ flakyScore: 'Композитный индекс нестабильности теста по истории прогонов.',
138
+ mtbf: 'Среднее время между нестабильными инцидентами теста.',
139
+ unstableRuns: 'Количество архивных прогонов, в которых тест был нестабильным.',
140
+ codeQuality: 'Плейсхолдер для будущих метрик качества тестового кода и соблюдения практик Playwright.',
141
+ timeToDetect: 'Время от падения до уведомления команды. В MVP-плане метрика требует интеграции с каналом алертов, поэтому без него показывается как ожидающая настройки.',
142
+ timeToFixFlaky: 'Медианное время от первого нестабильного инцидента до первого стабильного восстановления по доступной истории.',
143
+ ciWasteTime: 'Суммарное время, потерянное на лишние ретраи и повторные прогоны в CI по доступной истории.',
144
+ costOfFlakiness: 'Оценка потерь от нестабильных тестов на основе стоимости минуты CI и стоимости часа разработки.',
145
+ investigationCost: 'Оценка стоимости инженерного разбора нестабильных прогонов на основе assumptions по времени анализа и стоимости часа разработки.',
146
+ developerFriction: 'Прокси-нагрузка на команду из-за ретраев, повторных запусков и разбора нестабильных инцидентов.',
147
+ releaseConfidenceScore: 'Сводный прокси-сигнал риска релиза на базе доступной истории: помогает оценить, насколько текущему тестовому сигналу можно доверять перед решением о релизе.',
148
+ automationRoi: 'Возврат инвестиций в автоматизацию. По формуле из MVP-плана требует данных о сэкономленных ручных часах и стоимости поддержки.',
149
+ configAssumptions: 'Параметры сценарного пересчёта стоимости нестабильности.',
150
+ teamMetrics: 'Плейсхолдер для будущих командных метрик по ownership и здоровью автотестов.',
151
+ aiMetrics: 'Плейсхолдер для будущих AI/ML-метрик и прогнозных моделей.',
152
+ },
153
+ history: {
154
+ totalRuns: 'Всего прогонов в истории',
155
+ previousRun: 'Предыдущий прогон',
156
+ latestSource: 'Последний источник',
157
+ currentBranch: 'Текущая ветка',
158
+ current: 'Текущий',
159
+ previous: 'Предыдущий',
160
+ schemaVersion: 'Схема репорта',
161
+ },
162
+ tables: {
163
+ time: 'Время',
164
+ test: 'Тест',
165
+ file: 'Файл',
166
+ status: 'Статус',
167
+ flaky: 'Нестабильный',
168
+ duration: 'Длительность',
169
+ branch: 'Ветка',
170
+ commit: 'Коммит',
171
+ author: 'Автор',
172
+ source: 'Источник',
173
+ lastError: 'Последняя ошибка',
174
+ reason: 'Причина',
175
+ error: 'Ошибка',
176
+ count: 'Количество',
177
+ share: 'Доля',
178
+ tests: 'Тесты',
179
+ group: 'Группа',
180
+ testExamples: 'Примеры тестов',
181
+ },
182
+ charts: {
183
+ passRateDataset: 'Доля успешных тестов',
184
+ durationDataset: 'Длительность (с)',
185
+ flakyDataset: 'Количество нестабильных',
186
+ slowestDataset: 'Секунды',
187
+ },
188
+ performance: {
189
+ phaseBreakdownDescription: 'Фазы считаются эвристически по hook- и step-паттернам Playwright. Остаток времени относится к основному выполнению тестов, а доли показывают структуру фазового времени, а не wall-clock длительность всего прогона.',
190
+ suiteDurationDescription: 'Показываются самые тяжёлые наборы текущего среза. Группировка идёт по префиксу названия теста или по имени spec-файла, а проценты показывают долю внутри суммарного времени всех наборов.',
191
+ durationPerBrowserDescription: 'Срез строится по полю browser из репорта. Если browser не передан, AQA Pulse подставляет Chrome по умолчанию. Проценты показывают долю внутри суммарного времени всех браузеров/проектов, а не wall-clock прогон.',
192
+ runtimeBreakdownTitle: 'Срез по браузерам',
193
+ phaseLegendLabel: 'Структура длительности',
194
+ },
195
+ testsBrowser: {
196
+ title: 'Все тесты текущего прогона',
197
+ description: 'Полный список тестов текущего прогона с разбиением по статусам и отдельным flaky-срезом.',
198
+ all: 'Все',
199
+ passed: 'Успешные',
200
+ failed: 'Упавшие',
201
+ flaky: 'Нестабильные',
202
+ skipped: 'Пропущенные',
203
+ timedOut: 'Таймауты',
204
+ interrupted: 'Прерванные',
205
+ empty: 'Тесты для выбранного статуса не найдены.',
206
+ },
207
+ business: {
208
+ ciBreakdown: 'CI',
209
+ developerBreakdown: 'Разработка',
210
+ extraRetryTime: 'Потери времени на ретраи',
211
+ unstableRuns: 'Нестабильные прогоны',
212
+ extraRetries: 'Лишние повторы',
213
+ observedRuns: 'Наблюдений в истории',
214
+ activeDays: 'Активные дни в истории',
215
+ opsEyebrow: 'Ops',
216
+ opsTitle: 'Операционная цена нестабильности',
217
+ opsDescription: 'Сигналы, которые можно читать как текущую нагрузку на пайплайн и команду без assumptions и дополнительных интеграций.',
218
+ scenarioEyebrow: 'Scenario',
219
+ scenarioTitle: 'Сценарная экономика',
220
+ scenarioDescription: 'Денежные оценки зависят от assumptions по стоимости CI и времени инженеров, поэтому здесь показывается модель сценария, а не факт P&L.',
221
+ productRiskEyebrow: 'Product risk',
222
+ productRiskTitle: 'Риск для релиза и качества',
223
+ productRiskDescription: 'Сигналы, которые помогают понять, насколько текущее тестовое состояние годится для решения о релизе и где риск уже влияет на качество поставки.',
224
+ summaryTitle: 'Сценарный снимок потерь',
225
+ summaryDescription: 'Короткая сводка по денежной модели flaky: итоговая стоимость, стоимость разбора, потери CI и дневная цена нестабильности.',
226
+ businessOverviewTitle: 'Срез по бизнес-метрикам',
227
+ businessOverviewDescription: 'Часть показателей уже рассчитывается по истории прогонов, а метрики, для которых пока не хватает данных интеграций, явно помечаются как ожидающие настройки.',
228
+ releaseConfidenceBreakdownTitle: 'Прокси риска релиза — компоненты',
229
+ releaseConfidenceBreakdownDescription: 'Прокси-сигнал собирается из четырёх эвристик, которые помогают оценить риск релизного решения на текущих доступных данных.',
230
+ releaseConfidencePassRate: 'Pass Rate (вес 40%)',
231
+ releaseConfidenceFlakyRatio: 'Обратная доля flaky (вес 30%)',
232
+ releaseConfidenceErrorHealth: 'Качество ошибок (вес 15%)',
233
+ releaseConfidenceHistoryConsistency: 'Согласованность истории (вес 15%)',
234
+ releaseConfidenceTotal: 'Итоговый прокси-индекс',
235
+ releaseConfidenceHealthyThreshold: 'Порог 75+ обычно означает, что тестовый сигнал выглядит достаточно надёжным для решения о релизе.',
236
+ releaseConfidenceRiskThreshold: 'Если индекс ниже 75, релизное решение стоит отдельно перепроверить через flaky, ошибки и просадку pass rate.',
237
+ readinessTitle: 'Готовность сценарных и roadmap-метрик',
238
+ readinessDescription: 'Здесь видно, какие метрики уже считаются автоматически, а какие пока ждут интеграций, assumptions или дополнительных продуктовых сигналов.',
239
+ readinessReady: 'Готово',
240
+ readinessPartial: 'Частично',
241
+ readinessPending: 'Ожидает данных',
242
+ readinessTimeToDetectHint: 'Нужен канал уведомлений или алертинг, чтобы измерять путь от падения до сигнала команде.',
243
+ readinessTimeToFixHint: 'История уже позволяет считать восстановленные flaky-инциденты, если в архиве есть нестабильность и последующее восстановление.',
244
+ readinessCostHint: 'Статус зависит от того, заданы ли assumptions стоимости CI и времени разработки.',
245
+ readinessDeveloperFrictionHint: 'Считается по лишним ретраям, нестабильным прогонам и активным дням из доступной истории.',
246
+ readinessReleaseConfidenceHint: 'Считается из pass rate, flaky ratio, error health и согласованности последних прогонов как прокси риска релиза.',
247
+ readinessAutomationRoiHint: 'Для ROI нужны данные об экономии ручного тестирования, стоимости поддержки и совокупных затратах на автоматизацию.',
248
+ timeToDetectPending: 'Ожидает интеграции уведомлений',
249
+ timeToDetectHint: 'Чтобы считать метрику, нужно подключить канал оповещений и фиксировать время между падением и уведомлением команды.',
250
+ timeToFixHintPrefix: 'Восстановленных инцидентов в истории',
251
+ timeToFixPending: 'Недостаточно истории для расчёта',
252
+ timeToFixMedianHint: 'Медиана по восстановленным flaky-инцидентам из истории.',
253
+ automationRoiPending: 'Нужны assumptions по экономии',
254
+ automationRoiHint: 'Для ROI нужны сэкономленные ручные часы, стоимость поддержки и затраты на автоматизацию — этих данных в текущем JSON нет.',
255
+ costScenarioTitle: 'Стоимостной сценарий нестабильности',
256
+ costScenarioDescription: 'Ниже остаётся сценарный блок стоимости, который помогает быстро пересчитывать потери от flaky-тестов в деньгах.',
257
+ scenarioSummaryTitle: 'Текущий сценарий расчёта',
258
+ scenarioStatusReady: 'Денежная оценка настроена',
259
+ scenarioStatusPartial: 'Денежная оценка настроена частично',
260
+ scenarioStatusEmpty: 'Нужно задать assumptions',
261
+ scenarioStatusReadyHint: 'Заданы параметры CI и разработки — итоговая стоимость и структура считаются полностью.',
262
+ scenarioStatusPartialHint: 'Часть assumptions отсутствует, поэтому денежная оценка считается только частично.',
263
+ scenarioStatusEmptyHint: 'Пока можно анализировать только трение flaky, лишние повторы и потерянное время.',
264
+ impactTitle: 'Уровень влияния',
265
+ impactHigh: 'Высокое влияние',
266
+ impactMedium: 'Среднее влияние',
267
+ impactLow: 'Низкое влияние',
268
+ impactUnknown: 'Оценка не задана',
269
+ impactHighHint: 'Потери уже заметны и их стоит учитывать как отдельный фактор качества автотестов.',
270
+ impactMediumHint: 'Потери пока умеренные, но тренд уже может влиять на ритм команды и стабильность пайплайнов.',
271
+ impactLowHint: 'Потери пока ограничены, но сценарий всё равно полезно отслеживать в динамике.',
272
+ impactUnknownHint: 'Укажи assumptions, чтобы AQA Pulse показал денежную оценку и уровень влияния.',
273
+ formulaTitle: 'Из чего складывается стоимость',
274
+ formulaDescription: 'Прямые потери считаются отдельно по CI и по времени команды, а затем суммируются в общую стоимость.',
275
+ ciFormula: 'CI = потерянные минуты ретраев × стоимость минуты CI',
276
+ developerFormula: 'Разработка = нестабильные прогоны × минуты разбора × стоимость часа / 60',
277
+ totalFormula: 'Итог = стоимость CI + стоимость разработки',
278
+ overallCost: 'Общая стоимость',
279
+ ciCost: 'Стоимость CI',
280
+ developmentCost: 'Стоимость разработки',
281
+ costPerActiveDay: 'Стоимость на активный день',
282
+ costPerActiveDayHint: 'Нормализация по дням, в которых в истории были доступные прогоны.',
283
+ totalCostHint: 'Сумма стоимости CI и времени разработки, если денежные параметры заданы.',
284
+ ciCostHintPrefix: 'Дополнительное время ретраев',
285
+ developmentCostHintPrefix: 'Нестабильные прогоны',
286
+ activeDaysHintPrefix: 'Активные дни',
287
+ ciMinuteCost: 'Стоимость минуты CI',
288
+ devHourCost: 'Стоимость часа разработки',
289
+ analysisMinutes: 'Минут на разбор одного инцидента',
290
+ assumptionsMissing: 'Если стоимости не заданы, денежная оценка не рассчитывается, но индекс трения flaky, число лишних повторов и потерянное время продолжают считаться.',
291
+ scenarioRecalculation: 'Сценарный пересчёт',
292
+ resetAssumptions: 'Вернуть значения из отчёта',
293
+ recalcHint: 'Пересчёт выполняется локально в браузере и не меняет исходный dashboard-data.json.',
294
+ editorHint: 'Можно попробовать несколько сценариев: консервативный, реалистичный и дорогой enterprise-вариант.',
295
+ assumptionsConfiguredTitle: 'Параметры из текущего сценария',
296
+ assumptionsConfiguredHint: 'Эти значения участвуют в live-пересчёте блока стоимости прямо в браузере.',
297
+ ciShare: 'Доля CI',
298
+ developmentShare: 'Доля разработки',
299
+ presetTitle: 'Быстрые сценарии',
300
+ presetDescription: 'Выбери готовый пресет и при необходимости подстрой значения вручную.',
301
+ presetConservative: 'Консервативный',
302
+ presetRealistic: 'Реалистичный',
303
+ presetEnterprise: 'Enterprise',
304
+ presetApplied: 'Применён пресет',
305
+ topDriverTitle: 'Что сейчас сильнее всего влияет на стоимость',
306
+ topDriverMissingTitle: 'Денежный драйвер пока не определён',
307
+ topDriverMissingBody: 'Заполни assumptions, чтобы увидеть, какая часть потерь сейчас доминирует: CI или время команды.',
308
+ topDriverCiTitle: 'Главный драйвер — потери CI',
309
+ topDriverCiBody: 'Основной вклад в стоимость сейчас дают ретраи и повторные минуты пайплайна.',
310
+ topDriverDevelopmentTitle: 'Главный драйвер — время команды',
311
+ topDriverDevelopmentBody: 'Основной вклад в стоимость сейчас даёт ручной разбор нестабильных инцидентов и переключение внимания команды.',
312
+ topDriverBalancedTitle: 'Вклад CI и команды сейчас сопоставим',
313
+ topDriverBalancedBody: 'Стоимость распределена относительно равномерно: нестабильность одновременно бьёт и по пайплайну, и по времени разработки.',
314
+ releaseConfidenceDetails: 'Pass rate + обратная доля flaky + качество ошибок + согласованность истории как прокси риска релиза',
315
+ releaseConfidenceHint: 'Прокси риска релиза на текущих исторических данных',
316
+ assumptionsEmpty: 'Для денежной оценки укажи стоимость минуты CI, стоимость часа разработки и при необходимости минуты на разбор одного инцидента.',
317
+ },
318
+ manager: {
319
+ summaryTitle: 'Ключевые сигналы',
320
+ summaryDescription: 'Насколько надёжен текущий тестовый сигнал для решения о релизе, насколько высок риск качества и насколько нестабильность уже влияет на скорость поставки.',
321
+ releaseReadiness: 'Опора для релизного решения',
322
+ qualityRisk: 'Риск качества',
323
+ deliveryRisk: 'Риск для скорости поставки',
324
+ blockersTitle: 'Что мешает прямо сейчас',
325
+ blockersDescription: 'Приоритетные блокеры, которые сейчас сильнее всего влияют на стабильность качества и скорость поставки.',
326
+ changesTitle: 'Что изменилось к прошлому прогону',
327
+ changesDescription: 'Короткая сводка изменений к прошлому прогону.',
328
+ changesRunsMeta: 'Текущий: {current} • Предыдущий: {previous}',
329
+ readinessHealthy: 'Можно опираться',
330
+ readinessWarning: 'Нужна дополнительная проверка',
331
+ readinessCritical: 'Релизное решение под вопросом',
332
+ riskHealthy: 'Низкий',
333
+ riskWarning: 'Средний',
334
+ riskCritical: 'Высокий',
335
+ blockerAction: 'Открыть список тестов',
336
+ noBlockers: 'Критичных блокеров по текущему срезу не найдено.',
337
+ noChanges: 'Явных изменений к прошлому прогону не обнаружено.',
338
+ },
339
+ flakyInsights: {
340
+ title: 'Как читать flaky-блок',
341
+ historyLine: 'Таблица ниже ранжирует тесты по flaky-индексу на базе архивной истории AQA Pulse: показывается топ-10 тестов, а расчёт использует до 20 последних архивных прогонов.',
342
+ historyMissing: 'Если таблица пуста, это означает не нехватку числа прогонов как таковую, а то, что по доступным архивным данным не удалось собрать исторический рейтинг flaky-тестов.',
343
+ historyReady: 'Если таблица заполнена, её можно использовать как приоритетный backlog на разбор flaky-тестов по последним архивным прогонам.',
344
+ },
345
+ placeholderMetrics: {
346
+ codeQuality: [
347
+ 'M2.14 Оценка test smell',
348
+ 'M2.15 Соответствие POM',
349
+ 'M2.16 Плотность проверок',
350
+ 'M2.17 Оценка стратегии ожиданий',
351
+ 'M2.18 Гранулярность test.step',
352
+ ],
353
+ team: [
354
+ 'M2.27 Индекс здоровья команды',
355
+ 'M2.28 Тестов на разработчика',
356
+ 'M2.29 Flaky по командам',
357
+ 'M2.30 Межпроектная корреляция',
358
+ ],
359
+ ai: [
360
+ 'M3.1 Прогноз flaky на следующий запуск',
361
+ 'M3.4 Уверенность в первопричине',
362
+ 'M3.5 Подозрительные PR',
363
+ 'M3.8 Поиск аномалий',
364
+ ],
365
+ },
366
+ states: {
367
+ notesEmpty: 'Заметки для этого прогона отсутствуют.',
368
+ historyEmpty: 'История запусков пока пуста',
369
+ slowTestsEmpty: 'Медленные тесты не обнаружены',
370
+ problematicTestsEmpty: 'Проблемные тесты не обнаружены',
371
+ flakyTestsEmpty: 'Исторический список flaky-тестов пока пуст',
372
+ flakyTestsHistoryMissing: 'В текущем прогоне flaky уже есть, но по доступным архивным данным исторический рейтинг flaky-тестов пока не собрался.',
373
+ performanceBreakdownEmpty: 'Для выбранного среза пока не хватает данных, чтобы собрать breakdown длительности.',
374
+ failuresEmpty: 'Падений не обнаружено',
375
+ notSet: 'не задано',
376
+ yes: 'Да',
377
+ no: 'Нет',
378
+ noPreviousRun: 'Нет предыдущего прогона для сравнения',
379
+ noPreviousRunShort: 'Нет предыдущего прогона',
380
+ noChanges: 'Без изменений к прошлому прогону',
381
+ noChangesShort: '→ без изменений',
382
+ },
383
+ statusLabels: {
384
+ Passed: 'Успешные',
385
+ Failed: 'Упавшие',
386
+ Flaky: 'Нестабильные',
387
+ Skipped: 'Пропущенные',
388
+ 'Timed out': 'Таймауты',
389
+ Interrupted: 'Прерванные',
390
+ passed: 'Успешен',
391
+ failed: 'Упал',
392
+ flaky: 'Нестабильный',
393
+ skipped: 'Пропущен',
394
+ timedout: 'Таймаут',
395
+ 'timed out': 'Таймаут',
396
+ interrupted: 'Прерван',
397
+ unknown: 'Неизвестно',
398
+ },
399
+ },
400
+ testHistory: {
401
+ titleSuffix: 'история теста',
402
+ headerEyebrow: 'Observability Playwright • страница истории теста',
403
+ headerDescription: 'История конкретного теста по архиву запусков. Источник данных — серверный маршрут поверх существующего API.',
404
+ backToDashboard: '← Назад к дашборду',
405
+ filters: {
406
+ branch: 'ветка',
407
+ project: 'проект',
408
+ file: 'файл',
409
+ all: 'Все',
410
+ },
411
+ candidatesMeta: 'проект: {project} • файл: {file}',
412
+ statePages: {
413
+ notFound: {
414
+ heading: 'История теста не найдена',
415
+ message: 'В архивной истории не найдено ни одного прогона с таким названием и набором фильтров.',
416
+ extra: 'Попробуй убрать часть фильтров или открыть карточку из таблицы дашборда.',
417
+ },
418
+ conflict: {
419
+ heading: 'Найдено несколько одноимённых тестов',
420
+ candidatesEmpty: 'Кандидаты не найдены.',
421
+ },
422
+ testLabel: 'Тест',
423
+ },
424
+ metrics: {
425
+ archiveGaps: 'Пропуски архива',
426
+ totalRuns: 'Всего прогонов',
427
+ failedRuns: 'Упавшие прогоны',
428
+ flakyRuns: 'Нестабильные прогоны',
429
+ latestStatus: 'Последний статус',
430
+ passRate: 'Доля успешных',
431
+ failRate: 'Доля падений',
432
+ flakyScore: 'Индекс нестабильности',
433
+ latestError: 'Последняя ошибка',
434
+ latestFlakyEvent: 'Последний flaky-инцидент',
435
+ previousUnstableEvents: 'Предыдущие нестабильные события',
436
+ latestStableRecovery: 'Последнее стабильное восстановление',
437
+ currentStabilityStreak: 'Текущая стабильная серия',
438
+ unstableStreakBeforeRecovery: 'Нестабильная серия перед восстановлением',
439
+ timeline: 'История прогонов теста',
440
+ },
441
+ subtitles: {
442
+ totalRuns: 'прогонов найдено в истории',
443
+ failedRuns: 'failed / timedout / interrupted',
444
+ flakyRuns: 'прогоны со статусом flaky',
445
+ latestStatus: 'самый свежий найденный запуск',
446
+ passRate: 'доля прогонов со статусом passed',
447
+ failRate: 'доля неуспешных прогонов',
448
+ flakyScore: 'индекс нестабильности 0–100',
449
+ mtbf: 'среднее время между нестабильными прогонами',
450
+ },
451
+ tables: {
452
+ time: 'Время',
453
+ branch: 'Ветка',
454
+ commit: 'Коммит',
455
+ author: 'Автор',
456
+ status: 'Статус',
457
+ flaky: 'Нестабильный',
458
+ duration: 'Длительность',
459
+ retries: 'Повторы',
460
+ attempts: 'Попытки',
461
+ error: 'Ошибка',
462
+ empty: 'История пуста',
463
+ },
464
+ meta: {
465
+ time: 'время',
466
+ branch: 'ветка',
467
+ commit: 'коммит',
468
+ retries: 'повторы',
469
+ attempts: 'попытки',
470
+ latestStable: 'последний стабильный',
471
+ streakStart: 'начало серии',
472
+ currentLatestRun: 'текущий последний запуск',
473
+ afterUnstableEvent: 'после нестабильного события',
474
+ recoveryAt: 'восстановление',
475
+ latestUnstable: 'последний нестабильный',
476
+ oldestUnstable: 'первый в нестабильной серии',
477
+ },
478
+ actions: {
479
+ jumpToRow: 'Перейти к соответствующей строке в истории',
480
+ },
481
+ incident: {
482
+ title: 'Root Cause и сводка по инциденту',
483
+ tooltip: 'Сводка по последнему нестабильному эпизоду: вероятная категория причины, уровень уверенности и повторяемость по истории этого теста.',
484
+ severityLabel: 'Статус инцидента',
485
+ detailsTitle: 'Что видно по текущему инциденту',
486
+ evidenceTitle: 'Факты и подтверждения',
487
+ categoryLabel: 'Вероятная причина',
488
+ confidenceLabel: 'Уверенность',
489
+ unstableRunsLabel: 'Нестабильные прогоны',
490
+ matchingRunsLabel: 'Похожие эпизоды',
491
+ firstSeenLabel: 'Первое появление',
492
+ latestSeenLabel: 'Последний сигнал',
493
+ recoveryLabel: 'Последнее восстановление',
494
+ attemptsLabel: 'Проблемных попыток',
495
+ failureStepLabel: 'Точка падения',
496
+ primarySignalLabel: 'Основной сигнал',
497
+ jumpToFailureStep: 'Перейти к шагу в диагностике',
498
+ notCaptured: 'Не зафиксировано явно',
499
+ severity: {
500
+ active: 'Активно',
501
+ monitoring: 'Нужно наблюдать',
502
+ resolved: 'Восстановлено',
503
+ },
504
+ severityDescription: {
505
+ active: 'Последний запуск всё ещё падает.',
506
+ monitoring: 'Сигнал ослаб, но паттерн ещё стоит наблюдать.',
507
+ resolved: 'После сбоя уже были стабильные запуски.',
508
+ },
509
+ confidence: {
510
+ high: 'Высокая',
511
+ medium: 'Средняя',
512
+ low: 'Низкая',
513
+ },
514
+ category: {
515
+ network: 'Сеть / внешний ответ',
516
+ timeout: 'Таймаут / медленный ответ',
517
+ selector: 'Селектор / locator',
518
+ assertion: 'Проверка / assertion',
519
+ auth: 'Авторизация / сессия',
520
+ infrastructure: 'Окружение / раннер',
521
+ unknown: 'Сигнал неоднозначен',
522
+ },
523
+ },
524
+ diagnostics: {
525
+ latestRunTitle: 'Диагностика последнего запуска',
526
+ latestRunDescription: 'Подробности по попыткам самого свежего найденного прогона: ретраи, шаги и доступные артефакты.',
527
+ latestUnstableTitle: 'Диагностика последнего нестабильного эпизода',
528
+ latestUnstableDescription: 'Ближайший нестабильный запуск до текущего состояния. Удобно смотреть, что именно ломалось до восстановления.',
529
+ attemptTitle: 'Попытка #{attempt}',
530
+ duration: 'Длительность',
531
+ startTime: 'Старт',
532
+ stepOffset: 'От начала',
533
+ steps: 'Шаги',
534
+ attachments: 'Артефакты',
535
+ stepsTitle: 'Шаги попытки',
536
+ attachmentsTitle: 'Артефакты попытки',
537
+ retriesHint: 'Повторы — это дополнительные перезапуски после первой попытки. Попытки — общее число запусков теста внутри одного прогона, включая самую первую попытку.',
538
+ emptyAttempt: 'Для этой попытки нет дополнительных шагов, артефактов или текста ошибки.',
539
+ noCategory: 'Категория не указана',
540
+ failedStepBadge: 'Падение на этом шаге',
541
+ stepErrorBadge: 'Сопутствующая ошибка',
542
+ openAttachment: 'Открыть артефакт',
543
+ inlineImagePreview: 'Показать изображение внутри diagnostics',
544
+ expandImageHint: 'Нажми на изображение, чтобы открыть его крупнее.',
545
+ loadingImagePreview: 'Открываем изображение…',
546
+ imageLightboxTitle: 'Увеличенное изображение',
547
+ closeImageLightbox: 'Закрыть увеличенное изображение',
548
+ imagePreviewUnavailable: 'Не удалось загрузить изображение в preview. Открой артефакт отдельной вкладкой.',
549
+ inlineMarkdownPreview: 'Показать markdown внутри diagnostics',
550
+ loadingMarkdownPreview: 'Загружаем markdown для preview…',
551
+ markdownPreviewUnavailable: 'Не удалось загрузить markdown-preview для этого артефакта.',
552
+ attachmentLocationMissing: 'Источник артефакта не указан',
553
+ },
554
+ labels: {
555
+ error: 'ошибка',
556
+ flaky: 'flaky',
557
+ },
558
+ texts: {
559
+ errorMissing: 'Текст ошибки отсутствует.',
560
+ latestFlakyDescription: 'Последний нестабильный прогон был flaky: тест падал на одной из попыток, но в итоге завершился успешно.',
561
+ retryFlakyDescription: 'Тест завершился как flaky после повтора.',
562
+ recoveryAfter: 'Восстановление после {source} от {date}.',
563
+ unstableStreakBeforeRecovery: 'До последнего восстановления была серия из {count} нестабильных прогонов подряд. Ближайшее к восстановлению нестабильное событие: {label}.',
564
+ streakNotStarted: 'Текущий запуск ещё не входит в стабильную серию: самый свежий прогон остаётся нестабильным.',
565
+ streakWholeHistory: 'Тест идёт стабильно {count} прогонов подряд на всей доступной истории.',
566
+ streakAfterEvent: 'Тест идёт стабильно {count} прогонов подряд после {event}.',
567
+ recoveryFromError: 'последней ошибки',
568
+ recoveryFromFlaky: 'последнего flaky-прогона',
569
+ statusPrefix: 'статуса {status}',
570
+ },
571
+ states: {
572
+ unknown: 'Неизвестно',
573
+ yes: 'Да',
574
+ no: 'Нет',
575
+ },
576
+ },
577
+ };
@@ -0,0 +1,5 @@
1
+ export interface MetricIconDefinition {
2
+ svg: string;
3
+ }
4
+ export declare function resolveMetricIcon(metricKey: string | undefined, label: string): MetricIconDefinition | null;
5
+ export declare function renderMetricIconSvg(icon: MetricIconDefinition): string;