diff --git a/.tasks/STATUS.md b/.tasks/STATUS.md index d825572..ba90d07 100644 --- a/.tasks/STATUS.md +++ b/.tasks/STATUS.md @@ -33,11 +33,34 @@ _Updated: 2026-05-22_ --- -## 🔵 [board-viewer-review] — review checkpoint (umbrella) -**Status:** blocked -**Where I stopped:** дизайн зафиксирован, импл ещё не начата. -**Next action:** дождаться 🟢 у всех blocker-тасок (включая `board-viewer-pointers`). Прочитать спецификацию `.wiki/concepts/board-viewer.md`. Для каждой импл-таски: `git log --oneline`, прогнать тесты, сверить с acceptance criteria. Findings → follow-up tasks через `mcp__projects-meta__tasks_create`. -**Blocker:** board-viewer-pointers; board-viewer-gitea-reader; board-viewer-html-render; board-viewer-cron-deploy +## 🟢 [board-viewer-review] — review checkpoint (umbrella) +**Status:** done +**Where I stopped:** independent review выполнен subagent'ом (clean context, не имплементер). 43/43 тестов pass, secret hygiene clean, TDD-immutability чисто. 2 Major + 6 minor/nitpick findings зафайлены как follow-up таски ниже. +**Next action:** взять одну из ⚪ fix-тасок (readme-emoji или card-meta). +**Branch:** master + +--- + +## ⚪ [board-viewer-readme-emoji-fix] — fix stale emoji legend in README.md +**Status:** ready +**Where I stopped:** review нашёл; trivial 1-line fix. +**Next action:** обновить `README.md:5` на `⚪ open / 🔴 in-progress / 🟡 paused / 🔵 blocked / 🟢 done` + заполнить TBD "Quick start" блок. +**Branch:** master + +--- + +## ⚪ [board-viewer-card-meta-fix] — add owner pill + last-commit-marker to cards +**Status:** ready +**Where I stopped:** review нашёл acceptance gap — `project_owner` есть в JSON но не выводится; `last_commit_iso` только в relative age, не абсолютной дате. +**Next action:** TDD render + симметрично client-side board.js. См. `board-viewer-card-meta-fix.md`. +**Branch:** master + +--- + +## ⚪ [board-viewer-polish] — bundle of 6 minor/nitpick findings from review +**Status:** ready +**Where I stopped:** detailed list в task-файле; парсер comment, formatAge future-ts test, gitea-reader decisions-log clarification, filter status multi-select, docker healthcheck+stderr, parallel commit-iso. +**Next action:** забирать items по одному. См. `board-viewer-polish.md`. **Branch:** master --- diff --git a/.tasks/board-viewer-card-meta-fix.md b/.tasks/board-viewer-card-meta-fix.md new file mode 100644 index 0000000..dbeb4ac --- /dev/null +++ b/.tasks/board-viewer-card-meta-fix.md @@ -0,0 +1,43 @@ +# board-viewer-card-meta-fix + +## Goal + +Card meta сейчас содержит **title + project + age**. Acceptance criteria `board-viewer-html-render.md` строка 19-24 явно перечисляет 5 полей: + +- title (труб 80 chars) ✅ +- project badge ✅ +- **owner (если есть) — pill** ❌ (поле `project_owner` есть в TaskRecord и JSON, но не выводится) +- age (relative) ✅ +- **last-commit-marker — короткий hash или дата** ❌ (есть только relative age от `last_commit_iso`, абсолютной даты/хэша нет) + +html-render таска закрылась без этих полей — gap. Не было замечено при self-review (потому и нужен independent reviewer). + +## Key files + +- `src/render.ts:111-127` — `renderCard()` (server-side первая рендер-проходка) +- `static/board.js:76-89` — `renderCard()` (client-side rerender при toggle-grouping) +- `tests/render.test.ts` — добавить assertions для двух новых полей +- `static/board.css` — стиль для `.badge.owner` если нужно отличать визуально + +## Acceptance criteria + +- Card showing `project_owner` as a pill (CSS class `.badge.owner`), скрыт если поле пустое. +- Card showing last-commit-marker: minimum — ISO date `YYYY-MM-DD` (короткая дата, NOT relative). Hash недоступен из API без extra call → opt for date. +- Возможность размещения: либо как третий meta-span после age, либо как tooltip на age (`title=""`); решение имплементера. +- 2+ TDD tests: + - card with `project_owner` shows owner pill containing the value + - card with `last_commit_iso` shows date (e.g. `2026-05-22`) — separate from relative age +- Обе ветки (server-side `src/render.ts` + client-side `static/board.js`) синхронны. + +## Decisions log + +- 2026-05-22: задача из review-чекпойнта; severity=major (acceptance gap, не self-replied). +- Open: owner pill всегда показывать или только при variability (когда есть >1 owner в выборке)? — рекомендация: всегда показывать когда поле не null (нет смысла фильтровать на rendering этапе). + +## Completed steps + +- [ ] (фиксируется при выполнении) + +## Notes + +TDD obligatory — render логика, не visual. Тестируется через DOM-property assertions (как в `render.test.ts`). diff --git a/.tasks/board-viewer-polish.md b/.tasks/board-viewer-polish.md new file mode 100644 index 0000000..64cc8f2 --- /dev/null +++ b/.tasks/board-viewer-polish.md @@ -0,0 +1,60 @@ +# board-viewer-polish + +## Goal + +Bundle of minor / nitpick findings from `board-viewer-review` checkpoint. Each — small, individually below the task-creation threshold; collectively worth doing in one sweep. + +## Items + +### M1. Document parser's `**Status:**` field neglect + +- **Location:** `src/parser.ts` (in `parseOneBlock`) +- **Problem:** `**Status:**` text field is matched by `FIELD_RE` but never stored in `StatusBlock` (emoji is SoT). Future maintainer reads parser and wonders why. +- **Fix:** comment `// **Status:** text field intentionally ignored — emoji is canonical` near where it's matched, OR `delete fields['Status']` after parse to avoid the orphan field in local var. Choose the comment. + +### M2. `formatAge` future-timestamp behavior is undocumented + +- **Location:** `src/render.ts:31` + `static/board.js:49` +- **Problem:** `Math.max(0, …)` silently clamps future ISO to "0m". With server-clock drift на VDS vs Gitea это маскирует ошибку синхронизации. +- **Fix:** add one test asserting `formatAge(futureIso, now) === '0m'` to lock behavior, and add inline comment "// clamps to '0m' on future iso — see test". + +### M3. `gitea-reader` acceptance "per-task без записи в STATUS.md (legacy)" is impossible by design + +- **Location:** `.tasks/board-viewer-gitea-reader.md` Decisions log +- **Problem:** Acceptance line 42 promises tests for "per-task без записи в STATUS.md (legacy)" case, but the reader iterates STATUS.md blocks only — orphan per-task files are invisible by design (matches spec: STATUS.md is the index). +- **Fix:** append a decisions-log entry to `board-viewer-gitea-reader.md` clarifying this is intentional; STATUS.md is the entry point, orphan per-task files are out of scope. + +### M4. Client filter doesn't match status in by-status mode; "multi-select по статусам" not implemented + +- **Location:** `static/board.js:139-147` (`applyFilter`) +- **Problem:** Filter reads `.badge.status` / `.badge.project` text from DOM. In by-status mode there's no status badge → typing "blocked" matches nothing. Также acceptance в `board-viewer-html-render.md:27` обещает multi-select по статусам — не реализован. +- **Fix:** rebuild `applyFilter` to query the underlying `records` array (status always available regardless of view mode). Decide on multi-select: either ship a status-pill filter row, or amend acceptance criteria. Recommendation: add multi-select pills below the filter input — simple `