chore(archive): move untracked files + clean working tree\n\nArchived to agent-evolution/archive/:\n - test scripts, specs, data exports\n - dashboard-user-journey.md → .kilo/archive/\n\nClean: all non-ollama models verified (openrouter, openai removed)
This commit is contained in:
179
.kilo/archive/dashboard-user-journey.md
Normal file
179
.kilo/archive/dashboard-user-journey.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# APAW Dashboard — User Journey Specification
|
||||
|
||||
## Overview (Вкладка 1)
|
||||
|
||||
### Пользователь входит
|
||||
- Видит: статистика (34 агентов, 15 моделей, 347 истории, 18 рекомендаций)
|
||||
- Видит: timeline с последними изменениями
|
||||
- Видит: recommended agents (карточки)
|
||||
|
||||
### Hover
|
||||
- Карточка агента: подсветка, тень
|
||||
|
||||
### Click
|
||||
- Карточка агента: раскрывает подробности (модель, score, категория)
|
||||
|
||||
### Edge cases
|
||||
- Пустой агентData → "No agents available"
|
||||
- Нет рекомендаций → скрыть блок с recommended agents
|
||||
|
||||
### Console expectations
|
||||
- 0 ошибок
|
||||
- `renderOverview()` вызван без ошибок
|
||||
|
||||
---
|
||||
|
||||
## All Agents (Вкладка 2)
|
||||
|
||||
### Пользователь входит
|
||||
- Видит: search input, фильтр-кнопки (All, Core Dev, QA, Security, Analysis, Process, Cognitive)
|
||||
- Видит: агенты сгруппированы по категориям
|
||||
- **Все** фильтр-кнопки — активная "All" подсвечена
|
||||
|
||||
### Hover
|
||||
- Фильтр-кнопка: подсветка
|
||||
- Карточка агента: тень
|
||||
|
||||
### Click — фильтр
|
||||
- Клик "Core Dev":
|
||||
1. Кнопка "Core Dev" получает класс `active` (CSS: highlighted)
|
||||
2. Все секции категорий скрываются
|
||||
3. Показываются **только** агенты с категорией "Core Dev"
|
||||
4. **Никакой JS ошибки**
|
||||
- Клик "All": все секции категорий видны, "All" активна
|
||||
|
||||
### Click — поиск
|
||||
- Ввод "dev": фильтрация по имени + категории
|
||||
- Пустой результат: "No agents found"
|
||||
|
||||
### Edge cases
|
||||
- **Дважды кликнуть** на одну категорию → класс должен остаться active
|
||||
- **Клик между категориями** → предыдущая теряет active, новая получает
|
||||
- **Быстрый набор** в поиск → debounce 300ms
|
||||
|
||||
### Console expectations
|
||||
- `filterAgents()`: 0 ошибок
|
||||
- `filterCategory()`: не использует `event.target` (передаёт `this`)
|
||||
- Нет ReferenceError, TypeError
|
||||
|
||||
**🔴 BUG:** `event.target` в `switchHmTab()` — event может быть undefined
|
||||
|
||||
---
|
||||
|
||||
## Timeline (Вкладка 3)
|
||||
|
||||
### Пользователь входит
|
||||
- Видит: timeline с датами, моделями, commit-hash, reason
|
||||
|
||||
### Hover
|
||||
- Элемент timeline: подсветка
|
||||
|
||||
### Click
|
||||
- Элемент timeline: показать детали изменения (модал)
|
||||
|
||||
---
|
||||
|
||||
## Recommendations (Вкладка 4)
|
||||
|
||||
### Пользователь входит
|
||||
- Видит: карточки рекомендаций (агент → модель, impact, дельта score)
|
||||
- Видит: кнопки **"Apply Recommended Fixes"** и **"New Research Cycle"**
|
||||
|
||||
### Click — "Apply Recommended Fixes"
|
||||
- Открывается **модал** с чеклистом:
|
||||
- Каждая рекомендация: чекбокс + from → to модель + impact (low/medium/high)
|
||||
- Кнопка "Apply Selected"
|
||||
- Данные читаются из `agentData.agents[*].current.recommendations`
|
||||
|
||||
### Click — "New Research Cycle"
|
||||
- Открывается **модал** с выбором:
|
||||
- Source (OpenRouter, Ollama, etc.)
|
||||
- Focus (IF, SWE, etc.)
|
||||
- Кнопка "Start Research"
|
||||
|
||||
### Edge cases
|
||||
- Нет рекомендаций → пустой modal с сообщением "No recommendations"
|
||||
- **Функция `showResearchModal()` должна существовать**
|
||||
|
||||
### Console expectations
|
||||
- `showApplyModal()`: читает `agentData.agents` (не `INLINE_RECOMMENDATIONS`)
|
||||
- `exportRecommendations()`: генерирует JSON с реальными данными
|
||||
- **🔴 BUG:** `showResearchModal()` — функция ВЫЗЫВАЕТСЯ, но НЕ СУЩЕСТВУЕТ (ReferenceError)
|
||||
|
||||
---
|
||||
|
||||
## Heatmap (Вкладка 5)
|
||||
|
||||
### Пользователь входит
|
||||
- Видит: таблица Agent × Model
|
||||
- Красные/зелёные ячейки — weighted score
|
||||
- ★ = best fit, outlined = current model
|
||||
- ⚠ = low IF score
|
||||
|
||||
### Hover
|
||||
- Ячейка: tooltip с именем агента, моделью, score
|
||||
|
||||
### Click — ячейка
|
||||
- Открывается **модал** (cellDetailModal):
|
||||
- Заголовок: "Agent × Model"
|
||||
- Chart.js линейный график: динамика computeAgentScore по истории
|
||||
- История промтов: prompt_change из agent.history
|
||||
- Кнопка закрытия ✕
|
||||
|
||||
### Edge cases
|
||||
- Агент без истории → пустой график + "No history found"
|
||||
- Быстрый double-click → не открывать два модала
|
||||
|
||||
### Console expectations
|
||||
- `showCellDetail()`: вызывается с правильными аргументами
|
||||
- `renderCellChart()`: Chart.js рендерится без ошибок
|
||||
- **🔴 BUG:** HTML escaping в `renderHeatmap()` — переменные вставляются без экранирования
|
||||
|
||||
---
|
||||
|
||||
## Impact (Вкладка 6)
|
||||
|
||||
### Пользователь входит
|
||||
- Видит: Chart.js графики (Agent Score Distribution, Model Distribution, Migration Impact)
|
||||
|
||||
### Console expectations
|
||||
- 0 ошибок Chart.js
|
||||
|
||||
---
|
||||
|
||||
## Global — скрытые модальные окна
|
||||
|
||||
| Модал | Где открывается | Как закрывается |
|
||||
|-------|----------------|-----------------|
|
||||
| cellDetailModal | Клик ячейка heatmap | ✕ button, click outside |
|
||||
| applyModal | Кнопка "Apply Recommended Fixes" | ✕ button, click outside |
|
||||
| exportModal | Кнопка "Export JSON" (скрыта) | ✕ button, click outside |
|
||||
| researchModal | Кнопка "New Research Cycle" | ✕ button |
|
||||
| progressModal | Применение рекомендаций | ✕ button, closeProgressModal() |
|
||||
|
||||
**🔴 BUG:** `closeProgressModal()` — функция ВЫЗЫВАЕТСЯ, но НЕ СУЩЕСТВУЕТ (ReferenceError)
|
||||
|
||||
---
|
||||
|
||||
## Critical Path — минимальная проверка
|
||||
|
||||
1. Открыть http://localhost:3003
|
||||
2. Переключить все 6 вкладок (Overview → Agents → Timeline → Recommendations → Heatmap → Impact)
|
||||
3. На Agents: кликнуть "Core Dev" → проверить active class
|
||||
4. На Recommendations: кликнуть "Apply" → модал открылся без ошибки
|
||||
5. На Heatmap: кликнуть ячейку → модал с графиком открылся
|
||||
6. DevTools Console: 0 ошибок
|
||||
|
||||
---
|
||||
|
||||
## Regression Checklist
|
||||
|
||||
После любого изменения проверить:
|
||||
- [ ] Все 6 вкладок открываются без ошибок консоли
|
||||
- [ ] Фильтры на All Agents переключают active state
|
||||
- [ ] Кнопка "Apply Recommended Fixes" открывает модал
|
||||
- [ ] Кнопка "New Research Cycle" не вызывает ReferenceError
|
||||
- [ ] Клик на ячейку heatmap открывает модал
|
||||
- [ ] Модальные окна закрываются по ✕ и по клику снаружи
|
||||
- [ ] Поиск агентов работает (debounce)
|
||||
- [ ] Нет SyntaxError в консоли
|
||||
4637
agent-evolution/archive/data/evolution-export.json
Normal file
4637
agent-evolution/archive/data/evolution-export.json
Normal file
File diff suppressed because it is too large
Load Diff
32
agent-evolution/archive/tests/console-verification.cjs
Normal file
32
agent-evolution/archive/tests/console-verification.cjs
Normal file
@@ -0,0 +1,32 @@
|
||||
const { chromium } = require('playwright');
|
||||
const TARGET_URL = process.env.TARGET_URL || 'http://localhost:3003';
|
||||
|
||||
(async () => {
|
||||
const browser = await chromium.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] });
|
||||
const page = await browser.newPage();
|
||||
const errors = [];
|
||||
page.on('console', msg => { if (msg.type() === 'error') errors.push(msg.text()); });
|
||||
page.on('pageerror', err => { errors.push('PAGE: ' + err.message); });
|
||||
page.on('requestfailed', req => { errors.push('NET: ' + req.url()); });
|
||||
|
||||
await page.goto(TARGET_URL, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
for (const tab of ['overview','agents','history','recommendations','heatmap','impact']) {
|
||||
try {
|
||||
await page.click(`button[onclick="switchTab('${tab}')"]`);
|
||||
await page.waitForTimeout(1000);
|
||||
} catch(e) {}
|
||||
}
|
||||
await page.waitForTimeout(500);
|
||||
await browser.close();
|
||||
|
||||
console.log('TOTAL ERRORS:', errors.length);
|
||||
if (errors.length > 0) {
|
||||
errors.forEach((e, i) => console.log(i + ':', e.slice(0, 120)));
|
||||
} else {
|
||||
console.log('Console error monitor — Dashboard');
|
||||
console.log('Console errors: 0');
|
||||
console.log('Network errors: 0');
|
||||
}
|
||||
})();
|
||||
52
agent-evolution/archive/tests/final-check.cjs
Normal file
52
agent-evolution/archive/tests/final-check.cjs
Normal file
@@ -0,0 +1,52 @@
|
||||
const { chromium } = require('playwright');
|
||||
|
||||
(async () => {
|
||||
const browser = await chromium.launch({ headless: true, args: ['--no-sandbox'] });
|
||||
const page = await browser.newPage();
|
||||
const errors = [];
|
||||
page.on('console', msg => { if (msg.type() === 'error') errors.push(msg.text()); });
|
||||
page.on('pageerror', err => errors.push(err.message));
|
||||
page.on('requestfailed', req => { if (!req.url().includes('favicon')) errors.push('NET: ' + req.url()); });
|
||||
|
||||
await page.goto('http://host.docker.internal:3003', { waitUntil: 'domcontentloaded', timeout: 30000 });
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
const tabNames = ['overview', 'agents', 'history', 'recommendations', 'heatmap', 'impact'];
|
||||
|
||||
for (const tab of tabNames) {
|
||||
try {
|
||||
const ok = await page.evaluate((t) => {
|
||||
const btns = document.querySelectorAll('button.tab-btn');
|
||||
for (const btn of btns) {
|
||||
if (btn.getAttribute('onclick') && btn.getAttribute('onclick').includes("'" + t + "'")) {
|
||||
btn.click();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}, tab);
|
||||
if (!ok) errors.push('CLICK_FAIL: tab=' + tab + ' not found');
|
||||
await page.waitForTimeout(800);
|
||||
} catch (e) {
|
||||
errors.push('CLICK_FAIL: tab=' + tab + ' err=' + e.message.substring(0, 120));
|
||||
}
|
||||
}
|
||||
|
||||
// Click a heatmap cell
|
||||
try {
|
||||
const clicked = await page.evaluate(() => {
|
||||
const cell = document.querySelector('#hmTable tbody td:nth-child(2)');
|
||||
if (cell) { cell.click(); return true; }
|
||||
return false;
|
||||
});
|
||||
if (!clicked) errors.push('CLICK_FAIL: heatmap-cell not found');
|
||||
await page.waitForTimeout(1000);
|
||||
} catch (e) {
|
||||
errors.push('CLICK_FAIL: heatmap-cell err=' + e.message.substring(0, 120));
|
||||
}
|
||||
|
||||
await browser.close();
|
||||
|
||||
console.log('ERRORS:');
|
||||
console.log(JSON.stringify(errors));
|
||||
})();
|
||||
58
agent-evolution/archive/tests/final-dom-check.cjs
Normal file
58
agent-evolution/archive/tests/final-dom-check.cjs
Normal file
@@ -0,0 +1,58 @@
|
||||
const { chromium } = require('playwright');
|
||||
|
||||
(async () => {
|
||||
const browser = await chromium.launch({ headless: true, args: ['--no-sandbox'] });
|
||||
const page = await browser.newPage({ viewport: { width: 1280, height: 720 } });
|
||||
await page.goto('http://host.docker.internal:3003', { waitUntil: 'domcontentloaded', timeout: 30000 });
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 1. Heatmap tab + cell click
|
||||
await page.click("button[onclick*='switchTab(\\'\\'heatmap\\'\\')'\"]");
|
||||
await page.waitForTimeout(1000);
|
||||
const cell = await page.locator('#hmTable tbody tr:nth-child(2) td:nth-child(2)');
|
||||
if (await cell.count() > 0) {
|
||||
await cell.click();
|
||||
await page.waitForTimeout(1000);
|
||||
const modalVisible = await page.evaluate(() => {
|
||||
const m = document.getElementById('cellDetailModal');
|
||||
return m && getComputedStyle(m).display !== 'none';
|
||||
});
|
||||
console.log('heatmap cell click: cellDetailModal visible =', modalVisible);
|
||||
} else {
|
||||
console.log('heatmap cell: NOT FOUND');
|
||||
}
|
||||
|
||||
// 2. All Agents + filter 'Core Dev'
|
||||
await page.click("button[onclick*='switchTab(\\'\\'agents\\'\\')'\"]");
|
||||
await page.waitForTimeout(1000);
|
||||
const filterBtn = await page.locator('.filter-btn', { hasText: 'Core Dev' });
|
||||
if (await filterBtn.count() > 0) {
|
||||
await filterBtn.click();
|
||||
await page.waitForTimeout(500);
|
||||
const activeText = await page.evaluate(() => {
|
||||
const btn = document.querySelector('.filter-btn.active');
|
||||
return btn ? btn.textContent : 'NONE';
|
||||
});
|
||||
console.log('filter active button:', activeText);
|
||||
} else {
|
||||
console.log('filter Core Dev: NOT FOUND');
|
||||
}
|
||||
|
||||
// 3. Recommendations + Apply button
|
||||
await page.click("button[onclick*='switchTab(\\'\\'recommendations\\'\\')'\"]");
|
||||
await page.waitForTimeout(1000);
|
||||
const applyBtn = await page.locator('button', { hasText: 'Apply Recommended Fixes' });
|
||||
if (await applyBtn.count() > 0) {
|
||||
await applyBtn.click();
|
||||
await page.waitForTimeout(500);
|
||||
const applyModalVisible = await page.evaluate(() => {
|
||||
const m = document.getElementById('applyModal');
|
||||
return m && getComputedStyle(m).display !== 'none';
|
||||
});
|
||||
console.log('apply click: applyModal visible =', applyModalVisible);
|
||||
} else {
|
||||
console.log('Apply Recommended Fixes: NOT FOUND');
|
||||
}
|
||||
|
||||
await browser.close();
|
||||
})();
|
||||
17
agent-evolution/archive/tests/get-errors.cjs
Normal file
17
agent-evolution/archive/tests/get-errors.cjs
Normal file
@@ -0,0 +1,17 @@
|
||||
const { chromium } = require('playwright');
|
||||
(async () => {
|
||||
const browser = await chromium.launch({ headless: true, args: ['--no-sandbox'] });
|
||||
const page = await browser.newPage();
|
||||
const errors = [];
|
||||
page.on('console', msg => { if (msg.type() === 'error') errors.push(msg.text()); });
|
||||
page.on('pageerror', err => errors.push('PAGE: ' + err.message));
|
||||
page.on('requestfailed', req => { if (!req.url().includes('favicon')) errors.push('NET: ' + req.url()); });
|
||||
await page.goto('http://host.docker.internal:3003', { waitUntil: 'domcontentloaded', timeout: 30000 });
|
||||
await page.waitForTimeout(2000);
|
||||
for (const t of ['overview','agents','history','recommendations','heatmap','impact']) {
|
||||
try { await page.click(`button[onclick="switchTab('${t}')"]`); await page.waitForTimeout(1000); } catch(e) {}
|
||||
}
|
||||
await page.waitForTimeout(500);
|
||||
await browser.close();
|
||||
console.log(JSON.stringify(errors));
|
||||
})();
|
||||
25
agent-evolution/archive/tests/verify.cjs
Normal file
25
agent-evolution/archive/tests/verify.cjs
Normal file
@@ -0,0 +1,25 @@
|
||||
const { chromium } = require('playwright');
|
||||
const TARGET = 'http://host.docker.internal:3003';
|
||||
|
||||
(async () => {
|
||||
const browser = await chromium.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] });
|
||||
const page = await browser.newPage();
|
||||
const errors = [];
|
||||
page.on('console', msg => { if (msg.type() === 'error') errors.push(msg.text()); });
|
||||
page.on('pageerror', err => { errors.push('PAGE: ' + err.message); });
|
||||
page.on('requestfailed', req => { if (!req.url().includes('favicon')) errors.push('NET: ' + req.url().split('/').pop()); });
|
||||
|
||||
await page.goto(TARGET, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
for (const tab of ['overview','agents','history','recommendations','heatmap','impact']) {
|
||||
try { await page.click(`button[onclick="switchTab('')"]`); await page.waitForTimeout(800); } catch(e) {}
|
||||
}
|
||||
await page.waitForTimeout(500);
|
||||
await browser.close();
|
||||
|
||||
console.log('');
|
||||
console.log('TOTAL ERRORS:', errors.length);
|
||||
if (errors.length > 0) errors.forEach((e, i) => console.log(i + ':', e.slice(0, 120)));
|
||||
else console.log('Zero console, page, network errors on all 6 tabs');
|
||||
})();
|
||||
Reference in New Issue
Block a user