Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 173 additions & 0 deletions docs/todos/2026-06-18-issue-507-viewer-dashboard-errors/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Issue 507 Viewer Dashboard Errors Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Preserve dashboard scroll position during refreshes and show safe user-visible API error notifications in the viewer.

**Architecture:** Keep the fix inside the existing single-file viewer script. Add a small toast host/renderer beside the existing auth prompt patterns, add client-side timeout handling inside `api()`, and wrap dashboard refresh rendering with scroll capture/restore on the dashboard scroll container.

**Tech Stack:** TypeScript tests with Vitest, VM-executed browser script from `src/viewer/index.html`, DOM stubs in `test/helpers/viewer-sandbox.ts`, browser JavaScript in the viewer template.

---

## Files

- Modify: `src/viewer/index.html`
- Modify: `test/helpers/viewer-sandbox.ts`
- Modify: `test/viewer-session-id.test.ts`
- Update: `docs/todos/2026-06-18-issue-507-viewer-dashboard-errors/todo.md`

## Task 1: Red Tests For Viewer API Error Toasts

**Files:**
- Modify: `test/helpers/viewer-sandbox.ts`
- Modify: `test/viewer-session-id.test.ts`

- [ ] **Step 1: Extend the sandbox enough to observe abort timeouts and toast DOM**

Add mock element fields used by the viewer code: `scrollTop`, `scrollHeight`, `clientHeight`, `appendChild`, `remove`, `children`, and a minimal `AbortController`/`AbortSignal.timeout` surface if needed by tests.

- [ ] **Step 2: Write failing HTTP error toast test**

Add a test that sets `sandbox.fetch` to return `{ ok: false, status: 503 }`, calls `sandbox.apiGet("memories?<img src=x onerror=alert(1)>")`, and asserts a toast host contains escaped path/status text and no raw `<img`.

- [ ] **Step 3: Write failing network failure toast test**

Add a test that makes `sandbox.fetch` reject with `new Error("<script>offline</script>")`, calls `sandbox.apiGet("health")`, and asserts visible escaped text in the toast host with no raw `<script>`.

- [ ] **Step 4: Write failing timeout toast test**

Add a test using a never-settling `sandbox.fetch`, run pending timers, and assert `apiGet("health")` resolves to `null` and the toast host reports a timeout.

- [ ] **Step 5: Run red tests**

Run:

```bash
corepack pnpm exec vitest run test/viewer-session-id.test.ts
```

Expected before implementation: new toast tests fail because there is no toast host/notification and no browser-side timeout.

## Task 2: Red Tests For Dashboard Scroll Preservation

**Files:**
- Modify: `test/helpers/viewer-sandbox.ts`
- Modify: `test/viewer-session-id.test.ts`

- [ ] **Step 1: Write failing direct refresh scroll test**

Set `view-dashboard.scrollTop = 240`, provide successful dashboard API responses, call `sandbox.refreshDashboard()`, and assert `scrollTop` remains `240` after render.

- [ ] **Step 2: Write failing debounced refresh scroll test**

Set `state.activeTab = "dashboard"`, `view-dashboard.scrollTop = 180`, trigger `sandbox.scheduleDashboardRefresh()`, flush timers, await the load, and assert `scrollTop` remains `180`.

- [ ] **Step 3: Run red tests**

Run:

```bash
corepack pnpm exec vitest run test/viewer-session-id.test.ts
```

Expected before implementation: new scroll tests fail because `loadDashboard()` writes a loading state and render output without scroll restoration.

## Task 3: Minimal Viewer Implementation

**Files:**
- Modify: `src/viewer/index.html`

- [ ] **Step 1: Add toast CSS and host**

Add a bottom-right fixed toast container near existing top-level viewer markup. Style toasts with compact, accessible, non-card UI that fits existing viewer colors.

- [ ] **Step 2: Add safe toast helpers**

Add `showToast(title, message)` that creates DOM nodes and assigns text via `textContent`; do not concatenate untrusted text into `innerHTML`.

- [ ] **Step 3: Add browser-side API timeout**

Inside `api()`, create an `AbortController`, pass its signal to `fetch`, clear the timer in `finally`, and return `null` on timeout/failure. Do not override caller-provided headers. Preserve auth prompt behavior for 401.

- [ ] **Step 4: Surface API failures**

For non-OK responses, network failures, and timeouts, call `showToast()` with method/path/status-safe text. Do not include raw response bodies. Hide auth prompt only after successful responses as today.

- [ ] **Step 5: Preserve dashboard scroll**

Capture `#view-dashboard.scrollTop` before refresh rendering. Restore it after loading and after `renderDashboard()` if the active tab is still dashboard. Apply this through both direct `refreshDashboard()` and debounced `scheduleDashboardRefresh()` because both converge on `loadDashboardOnce()`.

## Task 4: Green Verification And Cleanup

**Files:**
- Modify: `docs/todos/2026-06-18-issue-507-viewer-dashboard-errors/todo.md`

- [ ] **Step 1: Run targeted viewer tests**

Run:

```bash
corepack pnpm exec vitest run test/viewer-session-id.test.ts test/viewer-security.test.ts test/viewer-graph-cooldown.test.ts
```

Expected after implementation: pass.

- [ ] **Step 2: Run repo-native checks**

Run:

```bash
corepack pnpm test
corepack pnpm run build
corepack pnpm run lint
```

Expected: pass, or record any unrelated/pre-existing failure with evidence.

- [ ] **Step 3: Run required security gates**

Run:

```bash
semgrep scan --config p/default --error --metrics=off .
gitleaks protect --staged --redact
```

Expected: pass. `gitleaks protect` runs after staging task-owned files.

- [ ] **Step 4: Update task record**

Update matrix statuses with command evidence, caveats, and residual risks.

## Task 5: GitHub PR Flow Closeout

**Files:**
- No code edits expected beyond task record if verification evidence changes.

- [ ] **Step 1: Commit task-owned changes**

Stage only task-owned files and commit with a scoped Conventional Commit message.

- [ ] **Step 2: Push branch to origin**

Push `issue/507-viewer-dashboard-errors` to `origin`.

- [ ] **Step 3: Create PR against `main`**

Use `gh pr create --repo wbugitlab1/agentmemory --base main --head issue/507-viewer-dashboard-errors`.

- [ ] **Step 4: Wait for CI and merge**

Wait for PR checks. If checks pass, merge into `origin/main` using repository defaults. If checks fail, fix task-owned failures or record blocker.

- [ ] **Step 5: Verify issue/thread closeout**

Verify Issue #507 is closed or linked by the merged PR. Archive the delegated Codex thread with the thread-management tool.

## Self-Review

- Spec coverage: Issue #507 scroll preservation, API error display, timeout behavior, and regression coverage are mapped to tests and implementation tasks.
- Placeholder scan: No `TBD` or open implementation placeholders remain.
- Type consistency: Viewer VM tests refer only to existing sandbox pattern names or browser globals that Task 1 adds.
- Scope: Single viewer surface; no schema, auth, REST endpoint, dependency, or external service changes.
95 changes: 95 additions & 0 deletions docs/todos/2026-06-18-issue-507-viewer-dashboard-errors/todo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Issue 507 Viewer Dashboard Errors

## Scope

- Repository: `/Users/A1538552/.codex/worktrees/dea7/agentmemory`
- Branch: `issue/507-viewer-dashboard-errors`
- Base: `origin/main` at `a029b7e117db99c65201ee3d9abb6bb93ff2e173`
- GitHub issue: `wbugitlab1/agentmemory#507`
- Spec path: none; source of truth is the current user delegation, Issue #507 body, and this task record.

## Sprint Contract

**Goal:** Preserve dashboard scroll position across refreshes and surface viewer API failures to users with safe, escaped toast notifications.

**Scope:** Viewer browser code in `src/viewer/index.html`, viewer VM sandbox support in `test/helpers/viewer-sandbox.ts`, and focused viewer tests.

**Non-goals:** No REST endpoint changes, no auth changes, no new dependencies, no new external services, no persistence/schema changes, and no upstream `rohitg00/agentmemory` writes.

**Acceptance criteria:**

- Manual dashboard refresh preserves `#view-dashboard.scrollTop`.
- Debounced dashboard refreshes used by polling and WebSocket events preserve `#view-dashboard.scrollTop`.
- API HTTP errors, network failures, and request timeouts produce visible bottom-right viewer notifications.
- Error notification content is text-escaped and does not render raw HTML from paths, HTTP bodies, or exception messages.
- Existing dashboard endpoint error banner remains intact for partial dashboard loads.

**Intended verification:**

- `corepack pnpm exec vitest run test/viewer-session-id.test.ts test/viewer-security.test.ts test/viewer-graph-cooldown.test.ts`
- `corepack pnpm test`
- `corepack pnpm run build`
- `corepack pnpm run lint`
- `semgrep scan --config p/default --error --metrics=off .`
- After staging: `gitleaks protect --staged --redact`

**Known boundaries:**

- Current-turn user instruction authorizes push, PR creation, merge, issue/thread closeout for task-owned changes.
- Remote writes must target `origin` (`wbugitlab1/agentmemory`) only.
- Do not read or mutate token-bearing package-manager config.
- If dependency setup is required because `node_modules` is missing, use `corepack pnpm install --frozen-lockfile --ignore-scripts` without manifest/lockfile changes.

**Stop conditions:**

- Any required check reports a real finding that cannot be fixed in scope.
- Remote target is not `wbugitlab1/agentmemory`.
- CI fails with an unclear or out-of-scope failure.
- A required security gate is unavailable or nonzero and cannot be resolved without current-turn user acceptance.

## Feature / Verification Matrix

| Change | Verification method | Status | Evidence |
| --- | --- | --- | --- |
| Preserve dashboard scroll on direct refresh | Failing then passing VM test in `test/viewer-session-id.test.ts` | pass | Red: `corepack pnpm exec vitest run test/viewer-session-id.test.ts` failed with `scrollTop` 0 vs expected 240. Green: same command passed 14/14. |
| Preserve dashboard scroll on debounced refresh path | Failing then passing VM test using `scheduleDashboardRefresh()`/timer flush | pass | Red: same focused run failed with `scrollTop` 0 vs expected 180. Green: same command passed 14/14. |
| Show API HTTP error toast | Failing then passing VM test around `apiGet()` | pass | Red: focused run failed because toast HTML was empty. Green: focused run passed 14/14. |
| Show API network failure toast | Failing then passing VM test around rejected `fetch` | pass | Red: focused run failed because toast HTML was empty. Green: focused run passed 14/14. |
| Show API timeout toast | Failing then passing VM test around abort timeout | pass | Red: focused run returned `{ unexpectedlyCompletedWithoutTimeout: true }`. Green: focused run passed 14/14. |
| Escape toast content | Failing then passing VM test with hostile path/error text | pass | Green focused tests assert no raw `<img` or `<script>` appears in toast HTML. |
| Existing dashboard endpoint banner preserved | Existing targeted viewer test suite | pass | `corepack pnpm exec vitest run test/viewer-session-id.test.ts test/viewer-security.test.ts test/viewer-graph-cooldown.test.ts` passed 40/40. |

## Subagent Ledger

| Workstream | Scope | Edits allowed | Expected output | Result | Residual risk |
| --- | --- | --- | --- | --- | --- |
| Explorer `019edc33-9e31-70d1-a3da-4e7c4e416b1d` | Read-only validation of Issue #507 against `HEAD == origin/main` | No | Evidence on scroll preservation, API error visibility, dashboard banner coverage, DOM escaping | Completed: issue valid. Dashboard banner partially covers endpoint-group failures, but scroll preservation and general API toasts/timeouts are missing. All refresh sources converge through dashboard content replacement. Fix must use textContent or `esc()` for untrusted text. | Source inspection inferred scroll loss; browser/runtime verification remains useful after implementation. |

## Progress

- 2026-06-18: Confirmed branch, remote, clean worktree, and issue validity.
- 2026-06-18: Recorded current Sprint Contract, matrix, and subagent result.
- 2026-06-18: Added Red tests for API HTTP/network/timeout toasts and dashboard scroll preservation; confirmed focused failures before implementation.
- 2026-06-18: Implemented safe viewer toasts, browser-side API timeout, and dashboard scroll capture/restore.
- 2026-06-18: Verification before base merge:
- `corepack pnpm exec vitest run test/viewer-session-id.test.ts` passed 14 tests.
- `corepack pnpm exec vitest run test/viewer-session-id.test.ts test/viewer-security.test.ts test/viewer-graph-cooldown.test.ts` passed 40 tests.
- `corepack pnpm test` passed 198 files / 2772 tests.
- `corepack pnpm run build` exited 0 with existing tsdown plugin timing and dynamic-import warnings.
- `corepack pnpm run lint` exited 0.
- `semgrep scan --config p/default --error --metrics=off .` completed with 0 findings.
- `git diff --check` exited 0.
- 2026-06-18: Merged `origin/main` (`ee72dba7`) into `issue/507-viewer-dashboard-errors` with no conflicts.
- 2026-06-18: Post-merge verification:
- `corepack pnpm exec vitest run test/viewer-session-id.test.ts test/viewer-security.test.ts test/viewer-graph-cooldown.test.ts test/viewer-token-savings.test.ts` passed 4 files / 41 tests.
- `corepack pnpm test` passed 199 files / 2773 tests.
- `corepack pnpm run build` exited 0 with existing tsdown plugin timing and dynamic-import warnings.
- `corepack pnpm run lint` exited 0.
- `semgrep scan --config p/default --error --metrics=off .` completed with 0 findings.
- 2026-06-18: Branch protection reported the PR branch behind `origin/main`; merged latest `origin/main` again with no conflicts.
- 2026-06-18: Final local verification after second base merge:
- `corepack pnpm exec vitest run test/viewer-session-id.test.ts test/viewer-security.test.ts test/viewer-graph-cooldown.test.ts test/viewer-token-savings.test.ts` passed 4 files / 41 tests.
- `corepack pnpm test` passed 199 files / 2773 tests.
- `corepack pnpm run lint` exited 0.
- `semgrep scan --config p/default --error --metrics=off .` completed with 0 findings.
- `corepack pnpm run build` exited 0 with existing tsdown plugin timing and dynamic-import warnings.
Loading
Loading