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

## Session Summary

Started from a `/doctor` report flagging the `ticktick` MCP server as failed ("Connection closed"). Diagnosed it as a missing-dependency crash, not an OAuth issue: the local stdio server `mcp-servers/ticktick/ticktick_mcp.py` is launched with bare `python` (Python 3.12) and that interpreter was missing `httpx` and (behind a try/except) `mcp`. Installed both into 3.12, created `mcp-servers/ticktick/requirements.txt`, and verified the server starts clean. The server now shows "Pending approval" (normal trust prompt) instead of crashing.

Mike then stated a hard requirement: git must never sit at an interactive credential prompt — his objection to Git for Windows is the Git Credential Manager popups that hang automation, not the tooling itself. Discovered a live symptom: a backgrounded Gitea Agent push was hung on a GCM prompt (commit unpushed). Stopped it, pushed via the vault Gitea API token, then built a durable, fleet-wide non-interactive auth solution: `setup-git-auth.sh` (primes the `store` credential helper from the vault token, scoped per-repo by origin host, only seizing the helper from GCM `manager`), a backgrounded `SessionStart` hook, and `GIT_TERMINAL_PROMPT=0` / `GCM_INTERACTIVE=Never` in `settings.json` env. Corrected an earlier wrong memory (had attributed the dislike to the bash/path-mangling layer). All subsequent pushes this session used native `git.exe` via PowerShell with zero prompts.

Mike disclosed the machine was recently reinstalled and asked to install anything missing. Found the reinstall installed Python deps into only one of the machine's two interpreters (`py`/3.14 for vault+scripts vs `python`/3.12 for MCP servers), which is exactly why ticktick (3.12) and `vault get-field` (3.14, missing PyYAML) were both broken. Installed PyYAML into `py`, `websocket-client` into `py` (cdp.py), and persisted `grok` to the User PATH. Ollama `list` came back empty, but the 5 expected models (47.8 GB) were intact on `D:\OllamaModels` — the tray app just needed a few seconds to hydrate; restarting it loaded all 5. No 48 GB re-download. Then amended the recovery script `windows-bootstrap.ps1` (Phase 7 both interpreters + pyyaml/websocket-client; Phase 3 persist grok PATH; Phase 6 prime git auth; Phase 8 full model set + hydration guard) and documented the gotchas in `machines/guru-5070.md`.

Finally, Mike asked for help managing Tailscale for a tech-inept two-machine client. Recommended one tailnet per client (never merge into ACG's own), MSP holds Admin, devices enrolled as tagged nodes via pre-auth keys pushed from GuruRMM. Authored `wiki/patterns/tailscale-client-management.md` + `tailscale-client-enroll.ps1` (idempotent unattended Windows MSI install + tagged auth-key join). Scanned GuruRMM for the client (Robert Wolkin): found client `Wolkin, Robert`/site `Main` with 3 online Win11 Home agents. Mike clarified scope: connect RSW-Laptop -> front for file + printer sharing; DESKTOP-V1JT1SE is Bob's personal machine (out of scope). Created the `robert-wolkin` client stub, then added a reusable "files + printer over Tailscale (Windows)" section (SMB over the tailnet, the 445-firewall-on-Tailscale-interface gotcha, local-account auth on Home, MagicDNS FQDN, Point-and-Print via RMM, Taildrive alternative).

## Key Decisions

- **ticktick fix is dependency install, not OAuth.** "Connection closed" on a local stdio MCP server = process crash before handshake. `/mcp` authenticate would not have helped.
- **Non-interactive git auth via repo-local `store` helper, not global change.** Kept global GCM untouched for other repos; scoped the credential to each repo's actual origin host. `GIT_TERMINAL_PROMPT=0` enforced via committed settings.json so even an unprimed machine fails fast instead of hanging.
- **Conservative helper override.** `setup-git-auth.sh` only switches the helper to `store` when it is empty or GCM `manager`, so a Mac osxkeychain setup is left alone — safe to run fleet-wide via SessionStart hook.
- **Two-interpreter Python installs in bootstrap.** Root cause of the reinstall breakage; de-dupe by `sys.executable` so a single install isn't run twice.
- **Did not re-download Ollama models.** Confirmed manifests + 47.8 GB on `D:\OllamaModels`; an empty `ollama list` right after login is a hydration-timing artifact, not "models gone."
- **One tailnet per client.** Isolation, billing, offboarding, IdP blast radius. Never merge a client into ACG's tailnet or share one tailnet across clients.
- **SMB over Tailscale for Wolkin (not Taildrive).** A shared printer forces SMB regardless, so use SMB for both files and printer; no subnet router because files/printer live on a node.
- **Session log to root** (`session-logs/`) — multi-topic (machine maintenance + git infra + a client), no single article implied; wiki articles were hand-authored inline during the session.

## Problems Encountered

- **ticktick MCP "Connection closed":** missing `httpx` then `mcp` in Python 3.12. Installed both; server starts clean.
- **Gitea Agent background push hung:** GCM credential prompt invisible in background. Stopped the agent (TaskStop), pushed with the vault API token, then made auth non-interactive permanently.
- **`git credential approve` rejected input:** PowerShell piping mangled the multiline credential ("missing protocol field"). Wrote directly to `~/.git-credentials` idempotently instead.
- **PowerShell commit failed on embedded double quotes:** `"see each other"` in a commit message split into stray pathspecs (PS 5.1 native-arg quoting bug). Used `git commit -F <msgfile>` / avoided embedded quotes.
- **`vault get-field` returned empty:** `yaml-query.py` (run via `py`/3.14) missing PyYAML. Installed pyyaml; added a `get`+grep fallback to setup-git-auth.sh.
- **Ollama `list` empty despite 47.8 GB on disk:** tray app server hydration delay (also the app vs CLI env). Restarted; all 5 models loaded. Documented as a bootstrap Phase 8 guard.
- **GuruRMM showed 3 agents, Mike expected 2:** clarified DESKTOP-V1JT1SE is Bob's personal machine, out of Tailscale scope.

## Configuration Changes

Created:
- `mcp-servers/ticktick/requirements.txt` — `httpx>=0.28`, `mcp>=1.27`
- `.claude/scripts/setup-git-auth.sh` — non-interactive git auth primer
- `.claude/memory/feedback_git_noninteractive_auth.md` — feedback memory (replaced the deleted `feedback_avoid_git_for_windows.md`)
- `wiki/patterns/tailscale-client-management.md` — MSP Tailscale pattern
- `wiki/patterns/tailscale-client-enroll.ps1` — GuruRMM enrollment script
- `wiki/clients/robert-wolkin.md` — client stub

Modified:
- `.claude/agents/gitea.md` — "Non-interactive auth" guidance block
- `.claude/settings.json` — `env` (GIT_TERMINAL_PROMPT=0, GCM_INTERACTIVE=Never) + SessionStart hook for setup-git-auth.sh
- `.claude/bootstrap/windows-bootstrap.ps1` — Phases 3, 6, 7, 8 amended
- `.claude/machines/guru-5070.md` — Known issues (interpreter split, ollama hydration, grok PATH, git auth)
- `.claude/memory/MEMORY.md` — index pointer
- `wiki/index.md` — Patterns + Clients rows

Deleted:
- `.claude/memory/feedback_avoid_git_for_windows.md` (superseded, never committed)

Machine state (not in repo):
- Python 3.12 (`python`): installed `httpx`, `mcp`
- Python 3.14 (`py`): installed `pyyaml`, `websocket-client`
- User PATH: appended `~\.grok\bin` (also `~\.local\bin`, `%APPDATA%\npm`)
- `~/.git-credentials`: two store entries (internal + public Gitea hosts); stale `%3a3000` entry removed
- Ollama: restarted; 5 models loaded from `D:\OllamaModels`

## Credentials & Secrets

- **Gitea shared push account:** `azcomputerguru`, API token used for non-interactive push. Vault: `services/gitea.sops.yaml` field `credentials.api.api-token` (also `credentials.password`). Token cached locally in `C:\Users\guru\.git-credentials` (plaintext, local-only, scoped to `172.16.3.20:3000` + `git.azcomputerguru.com`).
- **GuruRMM API admin:** vault `infrastructure/gururmm-server.sops.yaml` fields `credentials.gururmm-api.admin-email` / `admin-password`.
- No new secrets created. Tailscale auth key for Wolkin not yet generated (pending Mike standing up the tailnet).

## Infrastructure & Servers

- **Gitea (internal):** `http://172.16.3.20:3000` (origin for claudetools push this session). Public: `https://git.azcomputerguru.com` (vault repo origin).
- **GuruRMM API:** `http://172.16.3.30:3001` (JWT auth).
- **MariaDB:** `172.16.3.30:3306` (firewall opened to 172.16.0.0/22 per incoming coord message; not exercised this session).
- **GURU-5070 interpreters:** `py` -> Python 3.14 (`C:\Users\guru\AppData\Local\Programs\Python\...`); `python` -> Python 3.12.
- **Ollama:** `OLLAMA_MODELS=D:\OllamaModels`, `OLLAMA_HOST=0.0.0.0:11434`. Models: nomic-embed-text, qwen3:8b, qwen3:14b, codestral:22b, qwen3.6:latest.

### Robert Wolkin (GuruRMM)
- Client: `Wolkin, Robert` | Site: `Main` | site_id `2bb05f85-9fc8-4a7e-a5e5-ffe0c46431ac`
- Agents (Win 11 Home 25H2 build 26200, agent v0.6.57, all online 2026-06-06):
  - DESKTOP-V1JT1SE — `30f6af79-ab19-4ed3-9ebc-71b2bffc2d27` — Bob's personal machine (OUT of Tailscale scope)
  - RSW-Laptop — `043fd673-35a2-4d3d-8f91-ed73ce70cc1e` — Tailscale node (connects to front)
  - front — `877d311a-4b24-462c-97b1-d2a0f7730a71` — Tailscale node (file + printer host)

## Commands & Outputs

- ticktick crash: `python ticktick_mcp.py` -> `ModuleNotFoundError: No module named 'httpx'`, then `[ERROR] MCP package not installed`.
- Installs: `python -m pip install httpx`; `python -m pip install mcp`; `py -m pip install pyyaml`; `py -m pip install websocket-client`.
- Non-interactive push pattern: `$env:GIT_TERMINAL_PROMPT='0'; git -C D:\ClaudeTools push origin main` (succeeds silently; PS 5.1 wraps git stderr as NativeCommandError on success — trust `$LASTEXITCODE`).
- Prime creds: append `http://azcomputerguru:<token>@172.16.3.20:3000` to `~/.git-credentials` + repo-local `credential.helper=store`.
- Ollama fix: stop `ollama`/`ollama app`, start `ollama app.exe`, wait ~10s -> `ollama list` shows 5 models.
- GuruRMM lookup: `POST /api/auth/login` then `GET /api/agents`, filter `.client_name=="Wolkin, Robert"`.
- Firewall rule (planned for `front`): `New-NetFirewallRule -DisplayName "Tailscale SMB (files+print)" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 445 -RemoteAddress 100.64.0.0/10`.

## Pending / Incomplete Tasks

- **ticktick MCP:** restart session or `/mcp` reconnect to approve (currently "Pending approval"). Crash resolved.
- **grok:** on persistent User PATH but not callable in THIS already-running session; fine in new shells.
- **Tailscale (Wolkin):** Mike to stand up the tailnet on Robert's account, assign himself Admin, enable MagicDNS, set `tag:wolkin` ACL, generate reusable+pre-approved tagged auth key. Then: vault the key at `clients/robert-wolkin/tailscale-authkey.sops.yaml`, enroll RSW-Laptop + front via the enroll script, push post-connect SMB config.
- **OPEN ITEM (blocks printer step):** confirm whether the printer is USB-attached to `front` (Windows print share over SMB) or a separate network printer (install by IP on laptop, or subnet router on front).
- **Offered, not yet done:** stage the 4 RMM jobs (firewall + share/account on front; drive map + printer on laptop); wire enroll script into a GuruRMM script library vs ad-hoc.
- **Pre-existing WIP** (not from this session): `.claude/bootstrap/backup-to-bundle.ps1`, `restore-at-risk-work.ps1` (modified), `projects/msp-tools/guru-connect` (untracked) — swept by sync.sh `add -A`.

## Reference Information

- Commits (origin/main, pushed): `f3a175e` ticktick requirements; `9ff5a9f0` gitea agent auth docs; `162145b5` git-auth automation; `fd30af6a` bootstrap amendments + machine doc; `8d7e3805` tailscale pattern + script; `5c7e196b` wolkin stub; `32e71a13` wolkin RMM detail + scope; `f7540550` SMB files+printer pattern.
- Vault paths: `services/gitea.sops.yaml` (`credentials.api.api-token`), `infrastructure/gururmm-server.sops.yaml` (`credentials.gururmm-api.*`).
- Tailscale docs: subnet routers `tailscale.com/docs/features/subnet-routers`; kernel-vs-netstack `/docs/reference/kernel-vs-userspace-routers`; Windows MSI `/docs/install/windows/msi`; run unattended `/docs/how-to/run-unattended`; auth keys `/kb/1085/auth-keys`; firewall ports `/kb/1082/firewall-ports`; Taildrive `/docs/features/taildrive`.
- Tailscale MSI silent props: `TS_UNATTENDEDMODE=always`, `TS_NOLAUNCH`, `TS_LOGINURL`, `INSTALLDIR` (no auth-key property — use `tailscale up --authkey`).
- Wiki: `wiki/patterns/tailscale-client-management.md`, `wiki/patterns/tailscale-client-enroll.ps1`, `wiki/clients/robert-wolkin.md`.

---

## Update: 20:26 PDT — GuruRMM beta dashboard (spine hitbox + pin feature, 3-way reviewed) + Antigravity/agy dead-end

### Summary

Picked up the "RMM Beta Dashboard" project. Recovered context across the 2026-06-05 and 2026-06-06 GuruRMM logs: the dashboard redesign (Phases 1-5 — Shell&Spine, Omnibox, Triage, AgentDetail, design-system — plus ClientDetail reprioritization A/B/C and SPEC-016/025/026/027) is essentially complete and live on **beta v0.2.52**. The only pending dashboard action is promoting beta -> prod, which Mike deferred ("still polishing"). Confirmed no coord locks/messages on gururmm. Fast-forwarded the submodule from the pinned `226ba9f` (39 behind) to `origin/main` `ae025aa` to work on current code.

Mike flagged a polish issue: infra spine row hitboxes too small, dead zones "between" items. Diagnosed in `dashboard/src/components/ContextTree.tsx`: the nav `<Link>` only wrapped the label (row padding/gaps not clickable) and `mb-0.5`/`mt-0.5` left literal gaps. Fixed (Fitts's Law) by stretching the link to fill the row (`absolute inset-0 z-0`), making label/icon/status `pointer-events-none`, removing gaps, `py-1.5->py-2`. Committed `980152e`.

Mike then requested pinning spine items so they stay visible when a client is collapsed. Chose **Option B (inline-retain)** via an AskUserQuestion mockup: a collapsed client hoists its pinned descendants (pinned sites + agents) flat one indent under it; a collapsed site shows its pinned agents. Built via a Coding Agent: new `usePinnedSpineItems` localStorage hook (`gururmm.spine.pins`) + ContextTree render logic. Committed `5bd8589`.

Detoured on the Gemini-CLI deprecation banner (June 18). Installed the Antigravity CLI (`agy.exe` v1.0.6, official `antigravity.google/cli/install.ps1`, verified Google-domain + Cloud Run source before running). **Re-confirmed the 2026-06-05 finding**: `agy.exe` is the IDE embedded agent, NOT a headless CLI — produces zero stdout and hangs when invoked non-interactively (writes to a SQLite conversation store). The `agy` SKILL already routes to `@google/gemini-cli` (the real headless tool), which works. Mike has a **paid Gemini account**, so the plan is to stay on gemini-cli (defer any API-key hardening). Saved memory `reference_antigravity_agy_not_headless.md`. Verified both second-models authed: grok (`OK`) and gemini (`OK`).

Ran the **3-way Multi-AI review** (Gemini via `agy` + Grok + Claude Code Review Agent) on branch `polish/infra-tree-hitbox`. All three approved; core (mouse hitbox layering, hoist logic, hook re-render) confirmed correct. Applied the 5 agreed fixes (committed `679b919`, `tsc --noEmit` clean). Branch has 3 local commits, NOT merged/pushed — awaiting Mike's go to merge to main (which auto-builds beta). Finished by checking the `ff.py` Firefox driver to view Mike's tab — daemon not running, and clarified ff.py drives its own Playwright Firefox (can't attach to his regular Firefox window).

### Key Decisions

- **Append to this session's existing log** (same continuous session) rather than a new file, per /save rules.
- **Stay on gemini-cli; abandon Antigravity.** Paid Gemini account avoids the June 18 free-tier sunset; agy.exe is a confirmed non-headless dead-end. API-key hardening deferred ("cross that bridge later").
- **Pin layout = Option B (inline-retain on collapse)**, Mike's choice over a top "Pinned" tray.
- **Did the hitbox fix directly** (surgical, 1 file) but **delegated the pin feature build to a Coding Agent** and ran the **full 3-way review before any merge**, matching the dashboard's review culture.
- **Type-prefixed React keys in the hoist branch** (Grok was right: two `.map`s in one parent share a key namespace; Gemini/Claude were wrong that arrays auto-namespace).
- **Hook persistence moved to a `useEffect`** (pure updater) + cross-tab `storage` listener.

### Problems Encountered

- **agy.exe no stdout / hangs** when run from the Bash/PowerShell tools (exit 0, 0 bytes, or foreground hang). Root cause was already documented in the 2026-06-05 platform-day log (line 35) — the reinstall erased the machine-state knowledge so I re-walked it. Resolved: use `@google/gemini-cli`; recorded a memory to prevent the next rediscovery. Killed the hung agy.exe processes.
- **Submodule working tree 39 commits behind** origin/main (pinned). Fast-forwarded via `git checkout main && git pull --ff-only`.
- **Web docs for Antigravity were JS-rendered** (WebFetch returned nothing) and search results were polluted with spam npm packages. Resolved by verifying the install vector directly: `.google` gTLD domain + inspecting the install.ps1 (pulls from Google Cloud Run) before executing.

### Configuration Changes (this segment)

- New memory: `.claude/memory/reference_antigravity_agy_not_headless.md` + `MEMORY.md` index line.
- Installed `agy.exe` to `C:\Users\guru\AppData\Local\agy\bin` and the installer added that dir to the **User PATH** (dead-end binary; offered to remove, awaiting Mike).
- **Submodule `projects/msp-tools/guru-rmm` (separate repo `azcomputerguru/gururmm`, NOT the claudetools repo):** branch `polish/infra-tree-hitbox` with commits `980152e`, `5bd8589`, `679b919`. Files: `dashboard/src/components/ContextTree.tsx` (+~190/-36), new `dashboard/src/hooks/usePinnedSpineItems.ts`. **Local only — not pushed, not merged.** The claudetools sync does NOT touch this (different repo); the branch lives in the submodule working tree until Mike merges it.

### Pending / Incomplete Tasks (this segment)

- **Merge `polish/infra-tree-hitbox` -> gururmm `main`** when Mike approves -> webhook auto-builds beta. Then optionally promote beta -> prod (whole redesign still beta-only).
- **Remove the dead `agy.exe`** install + its User PATH entry (offered).
- **API-key hardening for gemini-cli** (paid account) deferred — the robust path past June 18 is `GEMINI_API_KEY`, not Antigravity. Not urgent.
- **ff.py**: to view a page, launch the daemon + nav (it can't see Mike's own Firefox window).
- Carried from earlier: promote dashboard beta->prod, Mike/Howard re-login for dev_admin reveal, confirm Robert Wolkin printer type (USB vs network), vault GuruRMM Postgres DATABASE_URL, SPEC-018 errors, rotate MSP360 key.

### Reference Information (this segment)

- Submodule branch `polish/infra-tree-hitbox` @ `679b919` (base `origin/main` `ae025aa`), repo `azcomputerguru/gururmm`, dir `projects/msp-tools/guru-rmm`.
- Dashboard beta v0.2.52; prod promote: `sudo /opt/gururmm/promote-dashboard.sh --confirm` on 172.16.3.30.
- `agy.exe`: `C:\Users\guru\AppData\Local\agy\bin\agy.exe` v1.0.6 (Antigravity CLI; NOT headless). Installer: `https://antigravity.google/cli/install.ps1`.
- Real second-model backends: `@google/gemini-cli` (`gemini` npm, v0.45.2, Google OAuth) via `ask-gemini.sh`; grok 0.2.22 via `ask-grok.sh`. Both verified `OK`.
- Memory added: `reference_antigravity_agy_not_headless.md`.
- ff.py: `.claude/scripts/ff.py`, daemon `localhost:9333`, profile `~/.claude/ff-profile`.

---

## Update: 2026-06-07 08:13 PDT — GuruRMM beta dashboard: alert-count fix (prod) + 3 sidebar features (rail expand, light-mode theming, resizable spine)

### Summary

Merged the prior session's infra-spine hitbox + pin branch to gururmm `main` (auto-built to beta). Mike then reported the Alerts page summary chips disagreed with the lists they open. Diagnosed TWO predicate mismatches making the list >= the chip: (1) the Critical/Warning chips counted `status != 'resolved'` but clicked `status:""` (all statuses incl. resolved), and (2) `get_alert_summary` scoped counts to the last 7 days while the alert list has NO time window. Fixed both — chips now click `status:"unresolved"`, and dropped the 7-day window from the summary SQL so all four chips deterministically equal their lists. Code Review APPROVED. Merged `6b4cee4`: the dashboard half to beta, the server `get_alert_summary` change to the SHARED API (= prod immediately).

Mike reported Warning still wrong post-deploy. Diagnosed via the live API + a `gururmm` RMM-agent tail of `/var/log/gururmm-build.log` as DEPLOY TIMING, not a bug: the fast Vite dashboard deployed first while the slow Rust server didn't restart with the dropped window until **14:31:33 UTC** (after he looked). Confirmed corrected: `summary.warning` 2->4, `total` 104->152 (the 2 "missing" warnings were just >7 days old; 0 resolved).

Built three sidebar features (Howard/Mike requests), each Coding-Agent-built + reviewed, each on its own branch -> build-verify -> merge to beta:
- **Rail expand** (`a6d355f`): the far-left FunctionRail gets a persistent toggle (localStorage `gururmm.rail.expanded`, cross-tab) widening it w-12->w-52 with inline labels; expanded mode inlines the "More" items; collapsed unchanged. Code Review APPROVED.
- **Sidebar light-mode theming** (`d2c9236`): the left panes were hardcoded always-dark. Gave the light theme a soft-grey `--sidebar-bg` (95%) / border (88%) and swapped sidebar-surface `text-white/N` -> `text-foreground/N` (1:1 opacity) across FunctionRail/InfrastructureSpine/ContextTree, PRESERVING the white-on-red alert badges + the dark hover tooltip. Dark mode unchanged.
- **Resizable spine** (`3c210e0`): drag the spine's right edge (180-480px, persisted `gururmm.spine.width`); width via inline style, transition off mid-drag; `setPointerCapture` + a teardown ref close the release-outside-window and unmount-mid-drag edge cases; keyboard arrows on the handle. Code Review APPROVED + the 2 robustness fixes applied.

### Key Decisions

- **Alert fix Part 2 = Option B (drop the 7-day window), Mike-approved despite prod impact** (the summary SQL is on the shared API; there is no separate beta API server). `status:"unresolved"` == the summary's `status != 'resolved'` because only 3 statuses exist (active/acknowledged/resolved — verified against schema + every write path).
- **Each sidebar feature is self-contained in its component** (FunctionRail/InfrastructureSpine self-manage state; no Layout.tsx change), reflowing via the existing flex row.
- **Theming preserves white-on-colored** (badge, tooltip) — only sidebar-surface text/bg/border became `foreground` tokens.
- **Did NOT promote beta -> prod** (Mike still reviewing); only the unavoidable server alert-count change is live on prod.
- Deferred the review's FunctionRail DRY (hoist PRIMARY_ITEMS) + `aria-current` nits to a future sidebar touch.

### Problems Encountered

- **Warning chip stale post-deploy** — deploy timing (slow Rust server restart at 14:31:33 UTC after the fast dashboard), not a logic bug. Confirmed via live API + RMM build-log tail.
- **First RMM dispatch failed** (`jq: Invalid numeric literal`) from nested JSON escaping in the command payload; rebuilt with `jq -n --arg` per the /rmm skill.
- Every feature branch needed a rebase onto `main` (CI version-bump commits advance `main` after each merge); each was a clean ff/rebase.

### Configuration Changes (submodule `projects/msp-tools/guru-rmm`, repo `azcomputerguru/gururmm` — NOT the claudetools repo)

- `dashboard/src/pages/Alerts.tsx` + `server/src/db/alerts.rs` — `6b4cee4` (alert chips + drop 7-day window)
- `dashboard/src/components/FunctionRail.tsx` — `a6d355f` (rail expand)
- `dashboard/src/index.css` + `FunctionRail.tsx`/`InfrastructureSpine.tsx`/`ContextTree.tsx` — `d2c9236` (theming)
- `dashboard/src/components/InfrastructureSpine.tsx` — `3c210e0` (resizable)
- All on `origin/main` (gururmm), deployed to beta; the `alerts.rs` change also on prod. The claudetools submodule pointer is left at pinned `226ba9f` (lagging — expected; not bumped).

### Infrastructure & Servers

- gururmm server `172.16.3.30:3001`; webhook build pipeline -> version bumps -> dashboard (beta web root `/var/www/gururmm/dashboard-beta`) + server (shared API restart). Server restarted **14:31:33 UTC** for the alert fix.
- `gururmm` RMM agent id `5e5a7ebc-95ea-40c8-b965-6ec15d63e157` (the server's own agent; used to tail the build log with no SSH).
- Alert data snapshot (2026-06-07): total 152, critical 23, warning 4 (3 active + 1 acknowledged), 0 resolved warnings.

### Commands & Outputs

- Alert diag: `GET /api/alerts/summary`, `GET /api/alerts?severity=warning&status=unresolved&limit=500` (JWT from vault `infrastructure/gururmm-server.sops.yaml credentials.gururmm-api.*`).
- RMM build-log tail: `POST /api/agents/<id>/command` with a `jq -n --arg`-built shell payload, then poll `/api/commands/<id>`.
- Per feature: `git checkout -b` -> Coding Agent -> Code Review Agent -> `npm run build` (exit 0) -> `git push origin <branch>:main` (ff) -> beta.

### Pending / Incomplete Tasks

- **Promote dashboard beta -> prod** (`sudo /opt/gururmm/promote-dashboard.sh --confirm` on `.30`) when Mike's happy — ships the whole redesign + these 4 dashboard changes. The server alert-count change is already on prod.
- FunctionRail DRY refactor (hoist `PRIMARY_ITEMS`) + `aria-current` (deferred review nits).
- Light-sidebar shade (95%) is a default — tweak after Mike's visual review on beta.
- `ff.py` visual verification of the light-mode sidebar offered (needs that Firefox profile logged into beta).
- Alert list `limit:200` pagination edge (a bucket >200 would show a chip number larger than the visible list) — pre-existing, noted.
- Carried: dev_admin re-login for credential reveal; Robert Wolkin printer type; vault GuruRMM `DATABASE_URL`; SPEC-018 errors; rotate MSP360 key.

### Reference Information

- gururmm `origin/main` this segment: `6b4cee4` alerts, `a6d355f` rail expand, `d2c9236` theming, `3c210e0` resizable spine (on top of prior `fa495ed`/`82e91c8` spine pin/hitbox, also merged this segment).
- New localStorage keys: `gururmm.rail.expanded`, `gururmm.spine.width` (+ `gururmm.spine.pins` from prior).
- beta `https://rmm-beta.azcomputerguru.com`; prod `https://rmm.azcomputerguru.com`.
