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