From 595844de0be176d5f594fc79a1608b70fe4b7572 Mon Sep 17 00:00:00 2001 From: Michael Chihlas Date: Fri, 1 May 2026 01:41:37 -0400 Subject: [PATCH 1/7] wip(handoff): audit TODO and Gitea issue validity Co-Authored-By: Codex --- .ai/HANDOFF.md | 24 ++++++++---------------- .ai/SESSION_LOG.md | 8 ++++++++ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.ai/HANDOFF.md b/.ai/HANDOFF.md index 3677ad80..32ad9cfc 100644 --- a/.ai/HANDOFF.md +++ b/.ai/HANDOFF.md @@ -2,32 +2,24 @@ # HANDOFF.md -**Last updated:** 2026-05-01 (session 6 — PR #156 QA'd, merged, branch deleted) +**Last updated:** 2026-05-01 (session 7 — backlog/Gitea issue validity audit) **Active task:** None. Pick next from `.ai/TODO.md` or roadmap. -**Just-merged:** PR #156 (suggested-fix `applied_pending` non-terminal outcome) merged into `main` as `3ba4532`. +**Just-reviewed:** `.ai/TODO.md`, inline code TODOs, and open Gitea issues were checked against current `main`. ## Where this session ended -PR #156 QA'd in the dev environment and merged. +Review-only audit completed; no source code changes were needed. Key findings: -1. Working tree had two commits' worth of pending work: the prior session's local review fixes (5 source files + 3 `.ai/` notes describing them) and this session's docker-exec docs (`.ai/PROJECT_CONTEXT.md` + `AGENTS.md`). Committed each as a separate logical commit, attributed to the agent that authored each. -2. Browser QA via `/qa`: 5 of 7 scripted checks PASS with concrete DB-level + UI-level evidence — PendingBanner rendering, "It worked" / "Update reason" / "Dismiss" actions, page-level Resolve auto-patch, Escalate intercept with new generalized copy. 2 entry-path checks (VerifyingBanner overflow → "Waiting to verify…", nudge "Still checking") deferred because they require live AI-generated chat state. The mutating handlers behind those entry paths are verified via the tested transitions, so risk is rendering-only. -3. Pushed `feat/fix-pending-verification` to remote. Required Gitea CI checks (`CI / frontend`, `CI / backend`) plus `CI / e2e` all green at merge. Merged via Gitea API as a merge commit (`3ba4532`). -4. Local `main` fast-forwarded to remote; `feat/fix-pending-verification` deleted locally and on the remote. - -**Validation evidence:** - -- `/gstack/qa-reports/qa-report-pending-verification-2026-04-30.md` — full report with screenshots in `screenshots/`. -- Gitea PR #156 state: `closed`, `merge_commit_sha=3ba45326`, `merged_at=2026-05-01T03:42:10Z`. +- `.ai/TODO.md`: pytest-xdist item is stale/resolved; lint cleanup is still valid but now 24 warnings, not 23; selector hardening, ResourceWarning filter audit, transactional rollback, testmon, `currentChatRef` observability, peer-tech escalation, and Escalation Mode mobile follow-up are still valid. +- Gitea open issues: #58, #60, #128, #129, #130 are still valid. #66 is partially resolved by `.rfflow` export/import; only template packs/marketplace remain. #127 is mostly resolved by assistant empty-state copy plus prompt boundaries; close or rewrite if an always-visible badge is still desired. +- Open Gitea PR #124 (`feat/cockpit-harness`) is stale/unmergeable against current `main` and overlaps/supersedes newer `/pilot` work. +- Inline TODOs still valid: post-session feedback prompt, FlowPilot analytics domain/time-entry TODOs, prompt-cache verification note unless live `anthropic.cache` evidence is confirmed, `ProposalDetail` modify-on-editor-save, and procedural ghost-step accept/dismiss handlers. ## Resume point — DO THIS NEXT -Pick a task from `.ai/TODO.md` or `03-DEVELOPMENT-ROADMAP.md`. Two non-blocking follow-ups for the just-shipped feature: - -- Drive checks 1 and 5 from the QA report in real pilot usage to close the entry-path UI rendering gap. -- Watch whether engineers lose track of multiple pending fixes across sessions; if so, revisit the cross-session "Follow-ups" rollup that was scoped out of PR #156. +Pick a still-valid task from the audit above. Highest cleanup leverage: remove/update stale TODO/Gitea items before implementing new work, especially `.ai/TODO.md` xdist and Gitea #66/#127. ## Environment notes (carry-forward) diff --git a/.ai/SESSION_LOG.md b/.ai/SESSION_LOG.md index 5fbad84a..579094da 100644 --- a/.ai/SESSION_LOG.md +++ b/.ai/SESSION_LOG.md @@ -12,6 +12,14 @@ --- +## 2026-05-01 05:40 UTC — Codex — Audit TODO backlog and Gitea issue validity + +- Compared `.ai/TODO.md`, inline code TODOs, and open Gitea issues against current `main`. +- Verified pytest-xdist is already shipped (`backend/requirements-dev.txt`, `backend/tests/conftest.py`, `.gitea/workflows/ci.yml`) so the `.ai/TODO.md` xdist item is stale. Ran frontend lint in Docker; current state is `0 errors, 24 warnings`, so the lint cleanup item remains valid but its count is stale. +- Verified Gitea issue status: #58, #60, #128, #129, #130 remain valid; #66 is partially resolved by current `.rfflow` import/export and should be narrowed to template packs/marketplace; #127 is mostly resolved by current UI copy and prompt boundaries unless an always-visible scope badge is still wanted. Open PR #124 is stale/unmergeable against current `main`. +- Verified inline TODOs still valid: post-session contextual feedback prompt, FlowPilot analytics domain/time-entry placeholders, prompt-cache verification note unless live telemetry has confirmed it, proposal `modify` flow editor wiring, and procedural ghost-step accept/dismiss buttons. +- Files touched: `.ai/HANDOFF.md`, `.ai/SESSION_LOG.md`. + ## 2026-05-01 03:45 UTC — Claude Opus 4.7 — QA, merge, and ship PR #156 pending-verification - Committed two logical units of pending work on `feat/fix-pending-verification`: prior session's local review fixes as `5bee264` (Codex-attributed, 5 source files + 3 `.ai/` notes) and this session's docker-exec docs as `15042af` (Claude-attributed, `.ai/PROJECT_CONTEXT.md` + `AGENTS.md`). Cleaned up a 20MB `core.22120` Chromium dump left behind by an earlier sandbox crash. From a21fe9345411023ad4c76d9427efa1e9e5c3637f Mon Sep 17 00:00:00 2001 From: Michael Chihlas Date: Fri, 1 May 2026 01:47:41 -0400 Subject: [PATCH 2/7] wip(handoff): clean stale TODOs and plan issue cleanup Co-Authored-By: Codex --- .ai/HANDOFF.md | 15 ++--- .ai/SESSION_LOG.md | 9 +++ .ai/TODO.md | 6 +- docs/plans/2026-05-01-issue-cleanup-plan.md | 74 +++++++++++++++++++++ 4 files changed, 92 insertions(+), 12 deletions(-) create mode 100644 docs/plans/2026-05-01-issue-cleanup-plan.md diff --git a/.ai/HANDOFF.md b/.ai/HANDOFF.md index 32ad9cfc..242d8a38 100644 --- a/.ai/HANDOFF.md +++ b/.ai/HANDOFF.md @@ -2,24 +2,23 @@ # HANDOFF.md -**Last updated:** 2026-05-01 (session 7 — backlog/Gitea issue validity audit) +**Last updated:** 2026-05-01 (session 8 — cleaned stale TODOs, wrote issue cleanup plan) **Active task:** None. Pick next from `.ai/TODO.md` or roadmap. -**Just-reviewed:** `.ai/TODO.md`, inline code TODOs, and open Gitea issues were checked against current `main`. +**Just-updated:** stale local TODOs were removed and an issue cleanup plan was added. ## Where this session ended -Review-only audit completed; no source code changes were needed. Key findings: +Cleanup follow-up completed: -- `.ai/TODO.md`: pytest-xdist item is stale/resolved; lint cleanup is still valid but now 24 warnings, not 23; selector hardening, ResourceWarning filter audit, transactional rollback, testmon, `currentChatRef` observability, peer-tech escalation, and Escalation Mode mobile follow-up are still valid. -- Gitea open issues: #58, #60, #128, #129, #130 are still valid. #66 is partially resolved by `.rfflow` export/import; only template packs/marketplace remain. #127 is mostly resolved by assistant empty-state copy plus prompt boundaries; close or rewrite if an always-visible badge is still desired. -- Open Gitea PR #124 (`feat/cockpit-harness`) is stale/unmergeable against current `main` and overlaps/supersedes newer `/pilot` work. -- Inline TODOs still valid: post-session feedback prompt, FlowPilot analytics domain/time-entry TODOs, prompt-cache verification note unless live `anthropic.cache` evidence is confirmed, `ProposalDetail` modify-on-editor-save, and procedural ghost-step accept/dismiss handlers. +- `.ai/TODO.md`: removed resolved pytest-xdist "Up next" item, removed resolved claim-role-gate item, updated frontend lint count to 24 warnings. +- Added `docs/plans/2026-05-01-issue-cleanup-plan.md` with tracker hygiene and implementation order. +- Tried to close Gitea #127 via API, but this environment has no Gitea token; API returned `401 token is required`. ## Resume point — DO THIS NEXT -Pick a still-valid task from the audit above. Highest cleanup leverage: remove/update stale TODO/Gitea items before implementing new work, especially `.ai/TODO.md` xdist and Gitea #66/#127. +If tracker auth is available, close #127 and close/archive stale PR #124; rewrite #66 to template packs / one-click install only. Then pick from the plan: low-risk maintenance first, then #130/#128 pilot UX friction. ## Environment notes (carry-forward) diff --git a/.ai/SESSION_LOG.md b/.ai/SESSION_LOG.md index 579094da..506cb40f 100644 --- a/.ai/SESSION_LOG.md +++ b/.ai/SESSION_LOG.md @@ -12,6 +12,15 @@ --- +## 2026-05-01 06:05 UTC — Codex — Clean stale TODOs and add issue cleanup plan + +- Removed the resolved pytest-xdist item from `.ai/TODO.md` and reset "Up next" to no selected task. +- Removed the resolved "Add role gate to handoff claim endpoint" backlog item from `.ai/TODO.md`. +- Updated the frontend lint cleanup TODO from 23 warnings to the current `npm run lint` result: 24 warnings, 0 errors. +- Tried to close Gitea #127 through the API, but this environment has no Gitea token; API returned `401 token is required`. +- Added `docs/plans/2026-05-01-issue-cleanup-plan.md` with safe tracker actions and a recommended order for clearing remaining issues. +- Files touched: `.ai/TODO.md`, `.ai/HANDOFF.md`, `.ai/SESSION_LOG.md`, `docs/plans/2026-05-01-issue-cleanup-plan.md`. + ## 2026-05-01 05:40 UTC — Codex — Audit TODO backlog and Gitea issue validity - Compared `.ai/TODO.md`, inline code TODOs, and open Gitea issues against current `main`. diff --git a/.ai/TODO.md b/.ai/TODO.md index 3f5ab56d..60a29ff6 100644 --- a/.ai/TODO.md +++ b/.ai/TODO.md @@ -5,11 +5,11 @@ ## Up next -- [ ] **Parallelize backend pytest with pytest-xdist.** ✅ landing as PR #151. Verified locally: backend suite 22 min → 4m 28s with `-n auto` on the 8-core homelab runner. Per-worker DB isolation via `PYTEST_XDIST_WORKER` in conftest.py. +None selected. Pick from the backlog below or `03-DEVELOPMENT-ROADMAP.md`. ## Backlog -- [ ] **Frontend lint warnings cleanup.** 23 `react-hooks/exhaustive-deps` warnings remain after PR #149 (mostly missing-deps in useEffect). Either fix them or audit them for known-safe ones and add eslint-disable comments. Not blocking CI today. +- [ ] **Frontend lint warnings cleanup.** `npm run lint` currently reports 24 warnings (0 errors): mostly `react-hooks/exhaustive-deps` plus a few unused eslint-disable directives. Either fix them or audit known-safe ones and add/remove eslint-disable comments intentionally. Not blocking CI today. - [ ] **Audit `filterwarnings` ignores added in `wip(handoff): restore backend suite to green`.** Codex added narrow `ResourceWarning` filters for unclosed socket/transport/event-loop noise from pytest-asyncio teardown. Worth periodically reviewing whether those are still needed (e.g. when bumping pytest-asyncio) — if a real warning appears in those forms it would be silenced. - [ ] **Add `data-testid` attributes to e2e-critical interactive elements.** PR #152 fixed five Playwright tests by chasing UI-text changes (`Sessions` → `Session History`, `Account Settings` → `Account Management`, `/assistant` → `/pilot`, "Flow Sessions" tab, Resume button on session cards). Each was a one-line selector update, but every UI churn re-breaks them. Adding stable `data-testid` attributes on the targeted elements (page heading wrappers, tab nav, primary action buttons) and switching tests to `getByTestId` would make these immune to copy/route renames. Scope it small — start with `SessionHistoryPage` heading, the AI/Flow Sessions tab buttons, the per-session `Resume` button, and the command-palette FlowPilot option. - [ ] **Per-test transactional rollback in `test_db` fixture.** Bigger engineering than xdist (which we already shipped). Instead of `DROP SCHEMA public CASCADE` per test, wrap each test in a savepoint and rollback at teardown. ~30-40% additional speedup on top of xdist for test-DB-heavy tests. Real refactor; only worth it if the suite gets significantly larger or runs more frequently. @@ -19,5 +19,3 @@ - [ ] **Allow peer-tech to escalate a colleague's session.** Today `POST /ai-sessions/{session_id}/handoff` in [endpoints/session_handoffs.py:48](backend/app/api/endpoints/session_handoffs.py#L48) filters by `AISession.user_id == current_user.id`, so only the session owner can escalate. Real MSP shops have peer hand-offs: Junior A is on lunch, Junior B sees the session is stuck and should be able to escalate it. Auth tweak: switch from session-owner check to `require_engineer_or_admin` + same-account scope. Add a `handed_off_by` audit column (already exists on `SessionHandoff`) so the original-owner-vs-actual-escalator distinction is preserved. Surfaced from /plan-eng-review on the Escalation-Mode wedge plan; v1 wedge demo doesn't need this (solo-founder pilot), but capture for v2 once 3+ pilots are live and a peer-claim need surfaces. - [ ] **Mobile/responsive design for EscalationQueue + handoff-context screen.** Pre-PMF wedge demo targets desktop only — MSP techs work on laptops/desktops in shop environments. Once 3+ paying customers exist and a tech requests mobile (likely on-call use case), spec the responsive behavior: stacked card layout below `sm:` breakpoint, full-bleed handoff-context overlay on mobile, swipe-to-claim gesture instead of Pick Up button. Surfaced from /plan-design-review on the Escalation-Mode wedge plan. - -- [ ] **(MOVED IN-SCOPE for Escalation Mode v1, 2026-04-27)** ~~Add role gate to handoff claim endpoint.~~ Codex review correctly flagged this as wedge-relevant (the race-condition story depends on auth gating). Now part of the Escalation Mode v1 build, not a deferred TODO. diff --git a/docs/plans/2026-05-01-issue-cleanup-plan.md b/docs/plans/2026-05-01-issue-cleanup-plan.md new file mode 100644 index 00000000..c0378a0b --- /dev/null +++ b/docs/plans/2026-05-01-issue-cleanup-plan.md @@ -0,0 +1,74 @@ +# Issue Cleanup Plan - 2026-05-01 + +## Tracker Hygiene + +These are safe tracker updates before any feature work: + +1. Close Gitea #127 (`feat: show AI content scope indicator`) unless an always-visible badge is still desired. + - Current code already has IT/MSP scope copy in the assistant empty state. + - `ASSISTANT_SYSTEM_PROMPT` also has an off-domain redirect boundary. +2. Rewrite Gitea #66 (`Tree Templates + Import/Export`) to the remaining scope only. + - `.rfflow` export/import is implemented in `tree_transfer.py` and exposed in the library UI. + - Remaining work: curated packs, authenticated one-click install from gallery, template versioning, marketplace/community path. +3. Close or archive open PR #124 (`feat/cockpit-harness`). + - It is unmergeable against current `main` and overlaps newer `/pilot` work. +4. Keep Gitea #58, #60, #128, #129, #130 open. + - They still describe real product gaps. + +## Recommended Order + +### 1. Low-Risk Maintenance + +- Clean frontend lint warnings. +- Audit/remove stale eslint-disable comments. +- Add missing `data-testid` selectors for e2e-critical controls. +- Add observability around unexpected `currentChatRef` guard mismatches. + +Why first: these reduce future regression cost and are small, well-bounded changes. + +### 2. Pilot UX Friction + +- #130: Add diagnostic command help affordances in `TaskLane` / action cards. +- #128: Decide whether task panel placement should be configurable or whether the existing responsive drawer is enough. +- EscalationQueue mobile design stays deferred until a customer asks for it. + +Why second: this improves the current FlowPilot wedge without changing core data models. + +### 3. Workflow Quality Signals + +- #58: Add structured "step is wrong" flags separate from thumbs-up/down helpfulness. +- Existing `StepFeedback` is not enough; it only records helpful/unhelpful and cannot capture incorrect/outdated/unclear/missing-info reasons. + +Why third: useful, but needs schema/API/UI/admin surfaces. + +### 4. Client Intelligence + +- #60: Recurring issue detection. +- Start with a read-only banner using existing `sessions.client_name + tree_id` filters. +- Add same-resolution detection only after confirming the available session outcome/node data is reliable enough. + +Why fourth: high value, but it touches session-start and close-out flows and needs careful false-positive handling. + +### 5. Documentation Structure + +- #129: Hierarchical guide navigation. +- Current `/guides` route is a card grid plus detail pages with sections and breadcrumbs, but not a collapsible guide tree. + +Why fifth: valid UX request, but less urgent than pilot workflow gaps. + +## Gitea Actions Needed + +The current environment does not have a Gitea token configured, so API writes fail with `401 token is required`. Once authenticated: + +```bash +curl -X PATCH \ + https://gitea.resolutionflow.com/api/v1/repos/chihlasm/resolutionflow/issues/127 \ + -H "Authorization: token $GITEA_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"state":"closed"}' +``` + +For #66, prefer editing the title/body instead of closing it: + +- Title: `feat: curated template packs and one-click install` +- Body: remove completed `.rfflow` export/import acceptance criteria and keep pack/install/versioning work. From 4d8b107121d54d2e019f102897088ab49a6012e6 Mon Sep 17 00:00:00 2001 From: Michael Chihlas Date: Fri, 1 May 2026 02:04:19 -0400 Subject: [PATCH 3/7] wip(handoff): start issue cleanup plan sections 1 and 2 Co-Authored-By: Codex --- .ai/HANDOFF.md | 15 +-- .ai/SESSION_LOG.md | 10 ++ docs/plans/2026-05-01-issue-cleanup-plan.md | 19 ++- frontend/src/App.tsx | 2 +- .../analytics/FlowAnalyticsPanel.tsx | 2 +- .../src/components/assistant/TaskLane.tsx | 114 ++++++++++++++++-- .../src/components/layout/CommandPalette.tsx | 3 +- .../components/library/AddToFolderMenu.tsx | 44 +++---- .../components/library/FolderEditModal.tsx | 16 +-- .../src/components/library/ShareTreeModal.tsx | 24 ++-- .../components/settings/BrandingSettings.tsx | 14 +-- .../tree-editor/NodeEditorPanel.tsx | 4 +- .../src/components/tree-editor/TreeCanvas.tsx | 2 +- frontend/src/hooks/useCachedQuota.ts | 2 +- frontend/src/pages/AccountSettingsPage.tsx | 2 +- frontend/src/pages/AssistantChatPage.tsx | 43 ++++--- frontend/src/pages/MyTreesPage.tsx | 2 +- frontend/src/pages/ProceduralEditorPage.tsx | 2 +- .../src/pages/ProceduralNavigationPage.tsx | 2 +- frontend/src/pages/SessionDetailPage.tsx | 2 +- frontend/src/pages/SessionHistoryPage.tsx | 4 +- frontend/src/pages/TreeEditorPage.tsx | 6 +- frontend/src/pages/TreeNavigationPage.tsx | 2 +- 23 files changed, 231 insertions(+), 105 deletions(-) diff --git a/.ai/HANDOFF.md b/.ai/HANDOFF.md index 242d8a38..bfca176f 100644 --- a/.ai/HANDOFF.md +++ b/.ai/HANDOFF.md @@ -2,23 +2,24 @@ # HANDOFF.md -**Last updated:** 2026-05-01 (session 8 — cleaned stale TODOs, wrote issue cleanup plan) +**Last updated:** 2026-05-01 (session 9 — started issue cleanup plan sections 1 and 2) **Active task:** None. Pick next from `.ai/TODO.md` or roadmap. -**Just-updated:** stale local TODOs were removed and an issue cleanup plan was added. +**Just-updated:** issue cleanup plan sections 1 and 2 were started and documented. ## Where this session ended -Cleanup follow-up completed: +Issue cleanup plan follow-up completed: -- `.ai/TODO.md`: removed resolved pytest-xdist "Up next" item, removed resolved claim-role-gate item, updated frontend lint count to 24 warnings. -- Added `docs/plans/2026-05-01-issue-cleanup-plan.md` with tracker hygiene and implementation order. -- Tried to close Gitea #127 via API, but this environment has no Gitea token; API returned `401 token is required`. +- Section 1: frontend lint is clean. Stale lint disables from the warning set were removed or replaced with justified comments, hook dependency warnings were resolved, e2e selectors were added for session history and the FlowPilot command-palette entry, and `AssistantChatPage` now logs unexpected `currentChatRef` stale async discards. +- Section 2: `TaskLane` action cards now have diagnostic help affordances for common commands (connectivity, DNS, IP config, event logs, services, and generic checks). #128 was documented as "keep existing responsive side-panel/bottom-drawer behavior unless pilot feedback proves a preference is needed." +- Updated `docs/plans/2026-05-01-issue-cleanup-plan.md` with section 1/2 status and validation. +- Validation passed: `docker exec -w /app resolutionflow_frontend npm run lint`, `docker exec -w /app resolutionflow_frontend npx tsc -b`, and `docker exec -w /app resolutionflow_frontend npm run build` (existing Vite large-chunk warning only). ## Resume point — DO THIS NEXT -If tracker auth is available, close #127 and close/archive stale PR #124; rewrite #66 to template packs / one-click install only. Then pick from the plan: low-risk maintenance first, then #130/#128 pilot UX friction. +If tracker auth is available, close #127 and close/archive stale PR #124; rewrite #66 to template packs / one-click install only. Then continue the plan at section 3: #58 structured "step is wrong" quality signals. After that, section 4 is #60 recurring issue detection and section 5 is #129 hierarchical guide navigation. ## Environment notes (carry-forward) diff --git a/.ai/SESSION_LOG.md b/.ai/SESSION_LOG.md index 506cb40f..57a41ebd 100644 --- a/.ai/SESSION_LOG.md +++ b/.ai/SESSION_LOG.md @@ -12,6 +12,16 @@ --- +## 2026-05-01 07:20 UTC — Codex — Start issue cleanup plan sections 1 and 2 + +- Started `docs/plans/2026-05-01-issue-cleanup-plan.md` sections 1 and 2. +- Cleaned frontend lint to zero warnings by removing stale lint disables, tightening hook dependencies, and adding justified comments where effects are intentionally keyed to route or owner identity. +- Added e2e selectors for session history controls and the FlowPilot command-palette entry. +- Added `AssistantChatPage` observability for unexpected `currentChatRef` stale async discards. +- Added `TaskLane` diagnostic help affordances for common command categories and documented #128 as "keep the existing responsive side-panel/bottom-drawer behavior until pilot feedback says otherwise." +- Verified `npm run lint`, `npx tsc -b`, and `npm run build` in `resolutionflow_frontend`; build only reported the existing Vite large-chunk warning. +- Files touched: frontend lint-cleanup files, `frontend/src/components/assistant/TaskLane.tsx`, `frontend/src/pages/AssistantChatPage.tsx`, `frontend/src/pages/SessionHistoryPage.tsx`, `frontend/src/components/layout/CommandPalette.tsx`, `docs/plans/2026-05-01-issue-cleanup-plan.md`, `.ai/HANDOFF.md`, `.ai/SESSION_LOG.md`. + ## 2026-05-01 06:05 UTC — Codex — Clean stale TODOs and add issue cleanup plan - Removed the resolved pytest-xdist item from `.ai/TODO.md` and reset "Up next" to no selected task. diff --git a/docs/plans/2026-05-01-issue-cleanup-plan.md b/docs/plans/2026-05-01-issue-cleanup-plan.md index c0378a0b..25fbf983 100644 --- a/docs/plans/2026-05-01-issue-cleanup-plan.md +++ b/docs/plans/2026-05-01-issue-cleanup-plan.md @@ -19,21 +19,28 @@ These are safe tracker updates before any feature work: ### 1. Low-Risk Maintenance -- Clean frontend lint warnings. -- Audit/remove stale eslint-disable comments. -- Add missing `data-testid` selectors for e2e-critical controls. -- Add observability around unexpected `currentChatRef` guard mismatches. +- Status: started 2026-05-01. +- Frontend lint is clean after removing stale disable comments and tightening hook dependencies. +- Added `data-testid` selectors for e2e-critical session history and FlowPilot command-palette controls. +- Added `AssistantChatPage` observability for unexpected `currentChatRef` guard mismatches so stale async discards are visible in the console. Why first: these reduce future regression cost and are small, well-bounded changes. ### 2. Pilot UX Friction -- #130: Add diagnostic command help affordances in `TaskLane` / action cards. -- #128: Decide whether task panel placement should be configurable or whether the existing responsive drawer is enough. +- Status: started 2026-05-01. +- #130: Added diagnostic command help affordances in `TaskLane` action cards. Each active diagnostic card can explain what it checks, what to look for, and when to use it. +- #128: Keep the existing responsive drawer behavior for now. `TaskLane` already uses a side panel on wide screens and a bottom drawer below the desktop breakpoint; do not add a top/side preference unless pilot feedback shows the current responsive layout is blocking workflow. - EscalationQueue mobile design stays deferred until a customer asks for it. Why second: this improves the current FlowPilot wedge without changing core data models. +Validation run: + +- `docker exec -w /app resolutionflow_frontend npm run lint` +- `docker exec -w /app resolutionflow_frontend npx tsc -b` +- `docker exec -w /app resolutionflow_frontend npm run build` + ### 3. Workflow Quality Signals - #58: Add structured "step is wrong" flags separate from thumbs-up/down helpfulness. diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index c3a27f1c..1487ac33 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -16,7 +16,7 @@ function App() { } else { setLoading(false) } - }, []) + }, [fetchUser, isAuthenticated, setLoading]) return } diff --git a/frontend/src/components/analytics/FlowAnalyticsPanel.tsx b/frontend/src/components/analytics/FlowAnalyticsPanel.tsx index 19923775..0c0a736c 100644 --- a/frontend/src/components/analytics/FlowAnalyticsPanel.tsx +++ b/frontend/src/components/analytics/FlowAnalyticsPanel.tsx @@ -39,7 +39,7 @@ export function FlowAnalyticsPanel({ treeId }: FlowAnalyticsPanelProps) { useEffect(() => { // eslint-disable-next-line react-hooks/set-state-in-effect setLoading(true) - // eslint-disable-next-line react-hooks/set-state-in-effect + setError(false) analyticsApi .getFlowAnalytics(treeId, period) diff --git a/frontend/src/components/assistant/TaskLane.tsx b/frontend/src/components/assistant/TaskLane.tsx index b0ecf5b4..4311cff4 100644 --- a/frontend/src/components/assistant/TaskLane.tsx +++ b/frontend/src/components/assistant/TaskLane.tsx @@ -31,6 +31,62 @@ interface ActionResponse { type TaskResponse = QuestionResponse | ActionResponse +interface DiagnosticHelp { + what: string + lookFor: string + usefulWhen: string +} + +function getDiagnosticHelp(action: ActionResponse): DiagnosticHelp { + const command = (action.command || '').toLowerCase() + + if (command.includes('test-netconnection') || command.includes('ping ')) { + return { + what: action.description || 'Checks whether the target is reachable over the network.', + lookFor: 'Successful replies, low packet loss, and whether the expected port shows as open.', + usefulWhen: 'Use it when you need to separate a service problem from a basic connectivity problem.', + } + } + + if (command.includes('nslookup') || command.includes('resolve-dnsname')) { + return { + what: action.description || 'Checks how DNS resolves the hostname or record.', + lookFor: 'Wrong IPs, NXDOMAIN responses, timeout errors, or different answers from different resolvers.', + usefulWhen: 'Use it when names fail but direct IP access may still work.', + } + } + + if (command.includes('ipconfig') || command.includes('get-netipconfiguration')) { + return { + what: action.description || 'Shows local IP, gateway, DNS, and adapter configuration.', + lookFor: 'APIPA addresses, missing gateways, wrong DNS servers, disconnected adapters, or stale leases.', + usefulWhen: 'Use it early when the symptom may be local network configuration.', + } + } + + if (command.includes('get-eventlog') || command.includes('get-winevent') || command.includes('eventlog')) { + return { + what: action.description || 'Reads Windows event logs for recent errors or warnings.', + lookFor: 'Events matching the failure time, repeated error IDs, service crashes, or permission failures.', + usefulWhen: 'Use it when the UI only shows a generic error and you need system-level evidence.', + } + } + + if (command.includes('get-service') || command.includes('restart-service')) { + return { + what: action.description || 'Checks service state on the affected machine.', + lookFor: 'Stopped services, restart loops, disabled startup types, or dependency failures.', + usefulWhen: 'Use it when a feature depends on a Windows service or background agent.', + } + } + + return { + what: action.description || 'Runs the diagnostic check suggested by FlowPilot.', + lookFor: 'Errors, unexpected values, failed checks, or output that differs from a known-good machine.', + usefulWhen: 'Use it when you need evidence before choosing the next troubleshooting step.', + } +} + interface TaskLaneProps { questions: QuestionItem[] actions: ActionItem[] @@ -98,6 +154,7 @@ export function TaskLane({ questions, actions, sessionId, onSubmit, onClose, loa const [showRunAll, setShowRunAll] = useState(false) const [showPreview, setShowPreview] = useState(false) const [copiedKey, setCopiedKey] = useState(null) + const [expandedHelpKey, setExpandedHelpKey] = useState(null) // ── Resize state ── const DEFAULT_WIDTH = 340 @@ -166,22 +223,22 @@ export function TaskLane({ questions, actions, sessionId, onSubmit, onClose, loa questions: questionsRef.current.map(q => ({ text: q.text, context: q.context })), actions: actionsRef.current.map(a => ({ label: a.label, command: a.command, description: a.description })), responses: tasksRef.current as unknown as Array>, - }).catch(() => { /* silent — best-effort save */ }) + }).catch(() => { /* silent - best-effort save */ }) }, 2000) return () => { if (saveTimerRef.current) clearTimeout(saveTimerRef.current) } - }, [sessionId, tasks]) // eslint-disable-line react-hooks/exhaustive-deps + }, [sessionId, tasks]) // Reset when new tasks come in from AI response — but preserve saved state useEffect(() => { if (sessionId) { const saved = loadTaskState(sessionId) if (saved && saved.length > 0) { - // eslint-disable-next-line react-hooks/set-state-in-effect -- intentional: syncs derived state from prop changes + // eslint-disable-next-line react-hooks/set-state-in-effect -- intentional: syncs task UI from persisted session state setTasks(saved) return } } - // eslint-disable-next-line react-hooks/set-state-in-effect -- intentional: syncs derived state from prop changes + setTasks([ ...questions.map((q): QuestionResponse => ({ type: 'question', text: q.text, context: q.context, state: 'pending', value: '', @@ -190,7 +247,7 @@ export function TaskLane({ questions, actions, sessionId, onSubmit, onClose, loa type: 'action', label: a.label, command: a.command, description: a.description, state: 'pending', value: '', })), ]) - }, [questions, actions]) // eslint-disable-line react-hooks/exhaustive-deps + }, [questions, actions, sessionId]) const updateTask = (idx: number, updates: Partial) => { setTasks(prev => prev.map((t, i) => i === idx ? { ...t, ...updates } as TaskResponse : t)) @@ -490,10 +547,49 @@ export function TaskLane({ questions, actions, sessionId, onSubmit, onClose, loa return (
-
{a.label}
- {a.description && ( -
{a.description}
- )} +
+
+
{a.label}
+ {a.description && ( +
{a.description}
+ )} +
+ +
+ + {expandedHelpKey === `${idx}` && (() => { + const help = getDiagnosticHelp(a) + return ( +
+
+

+ What it checks: + {help.what} +

+

+ What to look for: + {help.lookFor} +

+

+ When to use it: + {help.usefulWhen} +

+
+
+ ) + })()} {a.command && (
diff --git a/frontend/src/components/layout/CommandPalette.tsx b/frontend/src/components/layout/CommandPalette.tsx index d8c1d225..7bac283f 100644 --- a/frontend/src/components/layout/CommandPalette.tsx +++ b/frontend/src/components/layout/CommandPalette.tsx @@ -296,7 +296,7 @@ export function CommandPalette({ open, onClose }: CommandPaletteProps) { } return result - }, [query, searchFlows, searchSessions, searchAISessions, user]) + }, [query, searchFlows, searchSessions, searchAISessions, user, onPilotSession]) // Flatten all items for keyboard navigation const flatItems: PaletteItem[] = builtGroups.flatMap(g => g.items) @@ -401,6 +401,7 @@ export function CommandPalette({ open, onClose }: CommandPaletteProps) { return (
{/* Command with copy button */} {action.command && response.state !== 'skipped' && (
- + {action.command} @@ -282,7 +282,7 @@ export function ActionCardGroup({ actions, onSubmit, disabled, stale }: ActionCa {submitError && ( -
+
Failed to send
@@ -203,7 +203,7 @@ function ChatItem({
{confirming ? (
- Delete? + Delete?