# 2026-06-06 — GuruRMM ClientDetail reprioritization (beta) — RESUME NEEDED (reboot)

> **RESUME POINT:** The ClientDetail redesign is BUILT, 3-way reviewed, MERGED to `main`, and LIVE on
> rmm-beta (v0.2.51). Pick up at "Pending / Next" — the open items are: promote-to-prod decision, the
> "0 agents vs 16 offline" data-hygiene finding, a small agent-count/offline UX consistency fix, and the
> submodule-pointer bump. Nothing is half-finished mid-edit; the branch is merged and clean.

## User
- **User:** Mike Swanson (mike)
- **Machine:** GURU-5070
- **Role:** admin

## Session Summary

Reprioritized the GuruRMM dashboard **ClientDetail** page (the redesigned dashboard that's live on the
beta channel), driven by Mike's live critique of the Cascades of Tucson client page. Captured the page via
the CDP Chrome driver, then loaded full context on "yesterday's rebuild" (the 2026-06-05 multi-phase
dashboard redesign: 3-way audit → `dashboard-redesign-SPEC.md` → Phases 1-5, all merged to main and live
on beta). Confirmed the 5 UX "bugs" I initially cited were the *pre-redesign main-site* findings, not the
current beta — the redesign already fixed them.

Mike's ClientDetail critique: no priority ordering; Effective Policy should be collapsed (marker on
override); Code/#Sites/Created over-prominent as cards; Update Channel rarely used at client level; the
"Add Agent" button was dead (bounced to global `/agents`); Email Alerts exposed Graph integration creds
inline. We chatted through the mail-creds decision first: keep it **per-client for now** (plumbing
untouched — `alert_email_settings.rs`, secret encrypted + write-only via `has_secret`), **demote to a
collapsed flyout**, migrate to the Integration Catalog later (SPEC-005, still Proposed/not built).

Ran a **3-way design review** (Gemini + Grok + Claude) on a consolidated brief → produced
`clientdetail-reprio-SPEC-LOCKED.md`. Mike decided the two forks: (1) Add-Agent client selector **locked**
when launched from ClientDetail (mutable only from a future global entry), (2) Credentials stays **Tier-2**
(no Tier-1 peek). Built in 3 phases, each via a Coding Agent and each 3-way code-reviewed: **A** extract
`EnrollmentModal`/`MsiDownloadButton`/`install-urls` (behavior-preserving), **B** new `EnrollAgentModal`
wrapper (client-locked + mandatory target-confirm gate) + fix the dead Add-Agent, **C** the ClientDetail
layout. Grok caught real scope-safety issues in B (lock bypass + enroll-handoff race) and Gemini caught an
email-form load race in C — all fixed and re-verified.

Merged `redesign/clientdetail-reprio` → `main` (`3ff0da5`); the webhook rebuilt beta to **v0.2.51**
(`index-v7UH_Hfi.js`). CDP-screenshotted the live Cascades ClientDetail (saved PNGs). The new exceptions
band immediately surfaced a real discrepancy — Cascades shows "0 agents" (site-based) but "16 offline"
(client_id-based); a cross-client check (AZ Computer Guru = 2 critical/4 offline) proved the band filter is
correct, so it's a data/definition mismatch, not a UI bug.

## Key Decisions

- **Mail creds: Option A (demote, keep per-client).** Don't move to the Integration Catalog yet (SPEC-005
  isn't built); collapse the creds on ClientDetail, leave the per-client plumbing + write-only secret
  intact, tag for SPEC-005 migration.
- **Add-Agent client lock (the scope-safety call).** Enrollment is per-site only; from ClientDetail the
  client is LOCKED, with a mandatory "Enrolling into Client X › Site Y (code ZZZ)" confirm gate before any
  installer is shown. The mutable-client picker is reserved for a future global "Add Agent" entry. Decided
  against Mike's original freely-changeable-client idea after both reviewers flagged it as a footgun + a
  context-spine violation. The component is still globalizable (build the prop), just locked from the client page.
- **Lock made intrinsic** (Grok): the modal itself never renders the mutable picker when invoked locked —
  not relying on the caller passing a good value; call site passes the null-checked `client.id`.
- **Confirmed target is snapshotted** at confirm-click and EnrollmentModal renders from the snapshot (not a
  re-derived value) — closes a race where a sites-list change between confirm and render could strand the modal.
- **"What's broken" band = v1 from available data** (active alerts via `alertsApi.list({status,client_id})`
  + offline agents from the shared `["agents"]` fleet cache); full per-domain compliance rollup deferred to
  the SPEC-025 server endpoint (TODO left in code).
- **Credentials Tier-2 only** (Grok's position; Gemini wanted a Tier-1 peek — Mike chose Tier-2).
- **GuruRMM session log → root `session-logs/`** (per File Placement; the submodule is a separate repo).
  Wiki Phase 3 skipped (root path); the guru-rmm wiki article can absorb this later via `/wiki-compile project:guru-rmm --full`.

## Problems Encountered

- **Initial staleness:** I cited 5 UX bugs that were actually pre-redesign main-site findings. Resolved by
  pulling the full redesign doc set (SPEC/decisions/session/nits/VERIFIED audit) from the submodule `main`.
- **CDP screenshot inner-scroll quirk:** the page scrolls in an inner `<main>` (overflow-y-auto), so
  `window.scrollTo` did nothing; find the largest overflow element and set its `scrollTop`. Top vs bottom
  captured by scrolling that element.
- **Grok Phase B REQUEST-CHANGES:** lock bypass (nullable `lockedClientId` → fell back to global picker) +
  enroll-handoff desync race. Fixed: intrinsic lock (`isClientLocked` derived; no `setClientId`; picker only
  in `!isClientLocked`; call site `client.id`) + `confirmedSite` snapshot.
- **Gemini Phase C:** removing EmailAlertsCard's `if (isLoading) return null` (so the closed marker renders)
  exposed a form-overwrite race if a user expands+types mid-fetch. Fixed by guarding the expanded body with
  `settingsLoading` (keep the marker, gate the form). Also memoized the band counts.
- **Beta curl 403:** Cloudflare bot-blocks non-browser UAs; used the CDP browser (authenticated, real) to
  verify/screenshot instead. Build status confirmed via SSH to the build log on .30.

## Configuration Changes

All in the **gururmm submodule** (`projects/msp-tools/guru-rmm`), merged to `main`:
- NEW `dashboard/src/components/EnrollmentModal.tsx` (extracted from SiteDetail, Phase A)
- NEW `dashboard/src/components/MsiDownloadButton.tsx` (Phase A)
- NEW `dashboard/src/lib/install-urls.ts` (Phase A — BASE_URL vs API_BASE_URL, getEnrollUrls/getMsiInstallerUrl/cleanup consts)
- NEW `dashboard/src/components/EnrollAgentModal.tsx` (Phase B — locked-client enroll wrapper + confirm gate)
- MOD `dashboard/src/pages/SiteDetail.tsx` (consume extracted modal; -339 lines)
- MOD `dashboard/src/pages/ClientDetail.tsx` (Phase C full layout rewrite; +CopyButton/CollapsibleCard/ClientExceptionsBand)

Commits (gururmm): `cfde337` (A) → `dc5c849` (B) → `83b876b` (C) → merge `3ff0da5` on main. CI bump `be5ddc9` (v0.2.51).
Reference docs (machine-local, gitignored tmp): `.claude/tmp/redesign-docs/` — `clientdetail-reprio-SPEC-LOCKED.md`,
`clientdetail-reprioritization-brief.md`, `review-out/` (design review), `phaseA|B|C/` (per-phase reviews).
Screenshots: `.claude/tmp/cdp/cascades-NEW-top.png`, `cascades-NEW-bottom.png` (live beta render).
ClaudeTools repo: this session log only. **Submodule pointer NOT bumped** (lagging main, expected).

## Credentials & Secrets

- None newly discovered/created this session. No secrets typed into the UI (password rule honored, even via CDP).
- SSH `guru@172.16.3.30` works key-based for read commands from GURU-5070. Sudo (needed for prod promote) is in
  vault `infrastructure/gururmm-server.sops.yaml` (`credentials...password`).

## Infrastructure & Servers

- **Beta:** https://rmm-beta.azcomputerguru.com — dashboard beta channel; auto-builds from gururmm `main` on
  push (webhook → `build-dashboard.sh`), deploys to `/var/www/gururmm/dashboard-beta` on **172.16.3.30**.
  BETA banner; does NOT affect prod. Build log `/var/log/gururmm-build-dashboard.log`. Current: **v0.2.51**.
- **Prod:** https://rmm.azcomputerguru.com — promote-only via `sudo /opt/gururmm/promote-dashboard.sh --confirm`
  (do NOT hand-rsync). Currently still the pre-this-change dashboard until promoted.
- **CDP driver:** `.claude/scripts/cdp.py` (launch/status/nav/shot/click/type/key/eval), port 9222, profile
  `~/.claude/cdp-chrome-profile` (authenticated to beta), screenshots `.claude/tmp/cdp/`.
- Gitea (gururmm repo): internal `http://172.16.3.20:3000/azcomputerguru/gururmm.git`.

## Commands & Outputs

```
# beta build status / fingerprint (SSH, key-based read)
ssh guru@172.16.3.30 'tail -8 /var/log/gururmm-build-dashboard.log; grep -oE "assets/index-[A-Za-z0-9_-]+\.(js|css)" /var/www/gururmm/dashboard-beta/index.html'
# -> "Dashboard beta build complete: v0.2.51 (be5ddc9...)"; assets/index-v7UH_Hfi.js

# CDP: screenshot the live page the user is on
py .claude/scripts/cdp.py status            # shows active tab URL
py .claude/scripts/cdp.py nav "<url>"
py .claude/scripts/cdp.py eval "(()=>{const els=[...document.querySelectorAll('*')].filter(e=>e.scrollHeight-e.clientHeight>40 && /auto|scroll/.test(getComputedStyle(e).overflowY)); els.sort((a,b)=>b.scrollHeight-a.scrollHeight); const m=els[0]; window.__sc=m; m.scrollTop=0; return {sh:m.scrollHeight};})()"
py .claude/scripts/cdp.py shot .claude/tmp/cdp/out.png

# band cross-check (per-client filter verified): AZ Computer Guru = "2 critical · 4 offline" vs Cascades "16 offline"
```

## Pending / Incomplete Tasks  (RESUME HERE)

1. **Promote beta → prod?** When happy: `ssh guru@172.16.3.30` then `sudo /opt/gururmm/promote-dashboard.sh --confirm` (sudo pw in vault). NOT done — awaiting Mike's go.
2. **Data-hygiene finding (real):** Cascades shows "0 agents" (sum of site `agent_count`) but the exceptions band shows **"16 offline"** (agents with `client_id`=Cascades, any site). Band filter is CORRECT (cross-checked). So ~16 offline agents are tagged to Cascades but not under its single (0-agent) site — likely **siteless/orphaned agents** carrying `client_id`. Investigate (orphans? stale `site_id`? cleanup). This is a genuine data issue the new band exposed.
3. **Small UX consistency fix:** the strip's agent count (site-based) and the band's offline (client_id-based) use different denominators → a user can see "0 agents · 16 offline." Align both to the same source (likely client_id-based) so they're consistent. Small ClientDetail change; would go through the same branch→beta flow.
4. **Bump the claudetools submodule pointer** for gururmm → `3ff0da5`/current main, whenever desired (currently lagging — expected per CLAUDE.md; not required).
5. **Continue iterating** ClientDetail (e.g., the "what's broken" band can grow into the full compliance rollup once the SPEC-025 endpoint exists), or move to other pages.
6. (Separate threads from the prior 2026-06-05 session, tracked in coord todos, NOT this resume: GuruConnect remediation P0-P5 + issues #10-22; multi-session git isolation L2/L3 `e84ac521`.)

## Reference Information

- Beta: https://rmm-beta.azcomputerguru.com · Prod: https://rmm.azcomputerguru.com
- Cascades ClientDetail: `/clients/42e1b0e3-f8b7-4fc5-86bd-06bdbb073b7f`
- gururmm commits: A `cfde337`, B `dc5c849`, C `83b876b`, merge `3ff0da5`, CI bump `be5ddc9` (v0.2.51)
- Branch (merged): `redesign/clientdetail-reprio`
- Locked spec: `.claude/tmp/redesign-docs/clientdetail-reprio-SPEC-LOCKED.md`
- Reviews: `.claude/tmp/redesign-docs/{review-out,phaseA,phaseB,phaseC}/`
- Live screenshots: `.claude/tmp/cdp/cascades-NEW-{top,bottom}.png`
- Original redesign docs (in submodule `main`): `docs/dashboard-redesign-{SPEC,decisions,session}.md`, `docs/specs/SPEC-005-integration-catalog.md`
- Promote prod: `sudo /opt/gururmm/promote-dashboard.sh --confirm` on 172.16.3.30
