---
name: gc-audit
description: "Periodic end-to-end audit of the GuruConnect codebase + CI/CD (6 parallel passes: API surface, Rust, TypeScript, protocol/wire-format, security/remote-session, docs/roadmap; plus pipeline health). Explicit only via /gc-audit; optional --pass=<api|rust|ts|protocol|security|docs|pipeline>. Produces a report + updates FEATURE_ROADMAP/TECHNICAL_DEBT."

---

# GuruConnect End-to-End Audit

Periodic full-stack sanity check for **GuruConnect** — the standalone MSP remote-desktop
product (Rust/Axum relay server + Windows Rust agent + React/TS viewer component library,
Protobuf-over-WebSocket transport). Read-only by default — findings are written to a report
file and living docs are updated. No production code is changed.

> **This is GuruConnect, not GuruRMM.** GC diverges from the RMM audit in ways that matter —
> do NOT copy RMM assumptions. The biggest traps, called out where they apply below:
> - **GC uses runtime `sqlx::query()`/`query_as()` — NOT compile-time `sqlx::query!` macros**
>   (verified 2026-05-29; CLAUDE.md's "compile-time checked queries" line is stale, and v2 keeps runtime
>   sqlx). This matches RMM. A *new* `query!`/`query_as!` macro is therefore a deviation worth a `[LOW]`
>   (it reintroduces the `.sqlx`-cache-regen footgun + a build-time `DATABASE_URL` requirement), not the norm.
> - **Wire format is Protobuf**, not RMM's JSON `AgentMessage`/`ServerMessage` enums. The
>   integrity pass chases drift across four artifacts: `proto/guruconnect.proto` →
>   prost-generated agent code → prost-generated server code → **hand-written binary decode in
>   `dashboard/src/lib/protobuf.ts` (hardcoded message IDs)**. That manual TS decoder is GC's
>   signature failure mode.
> - **The dashboard is a React component library + server-served static HTML**
>   (`server/static/{login,dashboard,viewer}.html`), NOT a React Router SPA. There is no
>   `App.tsx` route tree and no `dashboard/src/api/client.ts`. The surface pass adapts.
> - **CI is Gitea Actions** (`.gitea/workflows/*.yml`) with a Windows runner on Pluto — not
>   RMM's `webhook-handler.py` + `build-shared.sh` pipeline.

---

## Execution Overview

```
Phase 0: Context load (coordinator reads key files)
Phase 1: Spawn 6 parallel audit agents (codebase passes A-F)
Phase 2: Run CI/CD pipeline audit (Agent G — sequential; SSH to deploy host)
Phase 3: Collect findings, aggregate, score
Phase 4: Write report + update living docs
Phase 5: Present summary to user
```

The audit is orchestrated here (Claude coordinator). All codebase passes run in parallel
subagents. The pipeline pass runs sequentially after (it touches live state via SSH / HTTP).
Each agent returns structured findings; the coordinator aggregates and writes the final report.

### Model (MANDATORY)

**Always run every audit pass on Opus.** Spawn each agent with `model: "opus"` (the `opus`
alias resolves to the latest Opus). This overrides default complexity-based routing — do NOT
downgrade any pass to Sonnet or Haiku, even the lower-stakes ones (API surface, TypeScript).
The coordinator orchestration also runs on Opus.

### Repo root

All paths below are relative to `projects/msp-tools/guru-connect/` unless prefixed otherwise.
GuruConnect is a **separate Gitea repo** (`azcomputerguru/guru-connect`), not a submodule of
the monorepo in the RMM sense — it lives at `projects/msp-tools/guru-connect/` with its own
`.git`. Deploy host: **172.16.3.30:3002**, systemd service `guruconnect.service`.

---

## Phase 0: Context Load (Coordinator Reads These)

Before spawning agents, read these yourself:

1. `CLAUDE.md` — GC project instructions, coding standards, ports, auth model
2. `docs/FEATURE_ROADMAP.md` — planned features (`[ ]`/`[~]`/`[x]` + P1-P3)
3. `TECHNICAL_DEBT.md` — living debt backlog + "Completed Items" section (repo root, NOT docs/)
4. `docs/ARCHITECTURE_DECISIONS.md` — ADR-001 (RMM↔GC contract), ADR-002 (release eng)
5. **All** `docs/specs/SPEC-*.md` (Glob them so new specs are auto-picked-up) — the architecture/feature
   specs. SPEC-001 = release-engineering parity; **SPEC-002 = the v2 modernization architecture — read it:
   it defines the in-flight rebuild and which v1 weaknesses are *already planned* to be replaced, so passes
   can distinguish known/planned from net-new.**
6. `specs/*/` shape-spec folders (`plan.md`/`shape.md`/`references.md`/`standards.md`) — pre-implementation
   plans (e.g. `specs/v2-secure-session-core/`, `specs/native-remote-control/`). `plan.md` is the
   implementation source-of-truth and tracks progress via `[DONE]` task markers — a reconciliation target
   for Agent F.
7. `.claude/CODING_GUIDELINES.md` **+ `.claude/standards/` — read `index.yml`, then the relevant standard
   files** (repo root). `.claude/standards/` is the **compliance baseline** the quality passes check code
   against (not just the looser CODING_GUIDELINES): `security/credential-handling`, `api/response-format`,
   `gururmm/sqlx-migrations`, `gururmm/platform-parity`, `conventions/{naming,no-emojis,output-markers}`,
   `git/commit-style`. Pass the relevant standards **and their key rules** to Agents B and C.

Capture from `server/src/api/mod.rs` (+ `server/src/main.rs` route registration) the complete
route list — every `.route(...)` plus the two WebSocket upgrade endpoints in
`server/src/relay/mod.rs` (`agent_ws_handler`, `viewer_ws_handler`). This becomes the
**authority route list** passed to Agents A and E.

Also extract every checkbox line from `FEATURE_ROADMAP.md` (with section + priority) into a
**roadmap claims list** — passed to Agent F for reconciliation against the code.

**During the v2 rebuild (SPEC-002):** extract a **planned-work list** from SPEC-002 and the active
`specs/*/plan.md` files — the known v1 weaknesses already scheduled for replacement (the relay-auth
CRITICALs, the broken web protobuf codec, the deploy stub, etc.). Pass this list to every pass. A finding
that matches already-planned work is still reported, but tagged **`[TRACKED — SPEC-002 / <spec>]`** instead
of presented as net-new, so an audit run mid-rebuild does not drown the report in things already decided.
**Net-new findings (in no spec/plan) are the signal that matters most.**

---

## Phase 1: Parallel Audit Agents

Spawn all six parallel agents (A, B, C, D, E, F) simultaneously in a single message. Each
agent receives the full context it needs inline — do not assume they share context. (Agent G —
Pipeline — runs sequentially afterward; it SSHes the live deploy host and hits HTTP endpoints.)

---

### Agent A — API Surface & Route Inventory

**Goal:** Find server endpoints with no UI/consumer exposure, handlers that are dead code, and
references in the dashboard/static HTML to routes that don't exist.

**Instructions for agent:**

1. Read `server/src/api/mod.rs` and `server/src/main.rs` — extract every `.route(path, method)`
   into a list grouped by resource (auth, users, sessions, downloads, releases, changelog,
   health, metrics). Include the two WS endpoints from `server/src/relay/mod.rs`.

2. **The dashboard is NOT a routed SPA.** Instead cross-reference route usage against:
   - `server/static/login.html`, `dashboard.html`, `viewer.html` — grep for `fetch(`, `/api/`,
     and `ws`/`wss` URLs the static pages call.
   - `dashboard/src/hooks/useRemoteSession.ts` — the WS connection URLs it opens.
   - `dashboard/src/components/*.tsx` — any REST calls.

3. Classify:
   - Server route never referenced by any static page / component / hook → **ORPHANED ROUTE**
     (dead code vs. intentionally external/integration — distinguish by context, e.g. routes the
     RMM integration calls per ADR-001 are not dead).
   - A `fetch`/WS URL in the frontend that matches no server route → **BROKEN CALL**.
   - Method mismatch (frontend POSTs to a GET route) → **METHOD MISMATCH**.

4. For each API resource group, assess whether the UI (static pages + viewer component) exposes
   the major operations. Flag resources with full server CRUD but no UI surface.

5. Return structured findings: `[SEVERITY] Description — file:line`.

---

### Agent B — Rust Code Quality & Standards

**Goal:** Find violations of GC's Rust standards and common quality issues across server + agent.

**Instructions for agent:**

Read `CLAUDE.md` (GC standards section), `.claude/CODING_GUIDELINES.md`, **and the relevant
`.claude/standards/` files the coordinator passed you** first. GC standards:
`tracing` for logging (not `println!`/`log`), `anyhow` in binaries, `thiserror` in libraries,
`async`/`await` preferred, clippy clean. **Audit against the concrete `.claude/standards/` rules and
cite the standard each finding violates** — `security/credential-handling` (no hardcoded secrets;
hashed/short-lived tokens; log auth attempts), `api/response-format` (consistent error envelope, no raw
`e.to_string()` to clients, kebab-case segments, idempotent migrations), `gururmm/sqlx-migrations`
(`IF NOT EXISTS`, server-applied, no manual pre-apply), `conventions/naming` (Rust/proto/DB casing),
`conventions/no-emojis`, `git/commit-style`.

**Compliance checks:**
- `.unwrap()` / `.expect()` outside `#[cfg(test)]` — panic in production. Flag each with context.
  `.expect("invariant reason")` on a truly-impossible path is acceptable if the reason is clear.
- `todo!()` / `unimplemented!()` in non-test production paths.
- `println!` / `eprintln!` used for logging instead of `tracing::` macros.
- `format!()` used to build SQL strings (injection risk — parameterize instead).
- **sqlx style:** GC's db layer uses **runtime `sqlx::query()`/`query_as()`** throughout, NOT
  compile-time `sqlx::query!` macros (verified 2026-05-29 — CLAUDE.md's "compile-time checked queries"
  claim is stale; v2 keeps runtime sqlx, matching RMM). So a **new `sqlx::query!`/`query_as!` macro is a
  deviation** worth `[LOW]` (reintroduces the `.sqlx`-cache-regen footgun + build-time `DATABASE_URL`),
  not the norm. Still flag `format!()`-built SQL (above) as the real injection risk.

**Auth coverage (server):**
- Read `server/src/api/mod.rs` + `server/src/auth/mod.rs`. Identify which route groups go through
  the `AuthenticatedUser` extractor / auth middleware vs. which are public (login, health,
  downloads, metrics may be intentionally public).
- Verify the **agent plane and viewer/admin plane are separated**: the agent WS
  (`agent_ws_handler`, auth via `support_code` OR `api_key`) and the viewer WS
  (`viewer_ws_handler`, auth via JWT) must not accept each other's credentials. Any non-public
  admin route reachable without JWT → `[CRITICAL]`.
- Confirm JWT secret + min-length enforcement at startup (`server/src/main.rs`) and the logout
  token blacklist (`server/src/auth/token_blacklist.rs`) is actually consulted on each request.

**Logging hygiene:**
- Grep `tracing::` calls that include JWT secrets, API keys, support codes, passwords, or PII
  (emails, usernames). These must be redacted.

**Error handling:**
- HTTP handlers returning 500 with raw `e.to_string()` — leaks internals to callers. Log
  server-side, return a generic message.

**Search paths:** `server/src/` and `agent/src/`. Exclude generated proto (`OUT_DIR`) and
`server/src/db/mod.rs` re-exports.

Return structured findings with file:line references.

---

### Agent C — TypeScript / Dashboard Quality

**Goal:** Find dashboard quality issues, with special focus on the hand-written protobuf decoder
(GC has no schema library on the TS side — correctness is manual).

**Instructions for agent:**

The dashboard (`dashboard/`) is a **React component library** (peer-dep React, no app router,
no bundler in-repo). Main artifacts: `components/RemoteViewer.tsx`, `components/SessionControls.tsx`,
`hooks/useRemoteSession.ts`, `lib/protobuf.ts`, `types/protocol.ts`.

**Standards baseline:** audit against the relevant `.claude/standards/` files the coordinator passed
(esp. `conventions/no-emojis`, `conventions/naming`, `conventions/output-markers` for any scripts) and
cite the standard each violation breaks.

**TypeScript quality:**
- `any` annotations in `dashboard/src/` — each is a type-safety gap (the binary/canvas code is
  exactly where `any` hides bugs).
- `@ts-ignore` / `@ts-expect-error` — note reason and whether still needed.
- `console.log` / `console.error` left in non-dev paths.
- Hardcoded server URLs instead of a passed `serverUrl` prop / config.

**Manual protobuf decoder correctness (`lib/protobuf.ts`) — HIGH PRIORITY:**
- The decoder parses binary frames with `DataView` and **hardcoded message IDs** (e.g.
  `MSG_VIDEO_FRAME`, `MSG_MOUSE_EVENT`, `MSG_KEY_EVENT`). Verify these IDs and field offsets
  match `proto/guruconnect.proto` field numbers / wire layout. A mismatch silently corrupts
  frames or events. (Agent D cross-checks the same surface from the proto side — coordinate via
  the report; this side checks the TS implementation correctness.)
- Bounds checking: does the decoder validate buffer length before reading offsets? A short/hostile
  frame should not throw an unhandled error or read OOB.

**Component patterns:**
- `RemoteViewer.tsx` canvas rendering: BGRA→RGBA conversion correctness; is the canvas sized to
  the frame? Are out-of-order frames (the `sequence` field) handled or dropped?
- `useRemoteSession.ts`: WebSocket lifecycle — reconnect handling, cleanup on unmount, error
  surfacing (a dropped session should not silently hang).
- Icon-only buttons without `aria-label`/`title`; inputs without `<label>`.

**Search paths:** `dashboard/src/` only.

Return structured findings with file:line references.

---

### Agent D — Protocol & Wire-Format Integrity

**Goal:** This is GC's signature pass. Detect drift across the four representations of the wire
protocol, plus migration/version integrity.

**Instructions for agent:**

**Four-way protocol drift (the core check):**
1. Read `proto/guruconnect.proto` — list every top-level `Message` `oneof` variant and each
   message's fields with their **field numbers**. Note `session_type`, `VideoFrame`/`RawFrame`/
   `EncodedFrame`, `MouseEvent`, `KeyEvent`, `AgentStatus`, `AdminCommand`, `UpdateInfo`,
   `Heartbeat`/`HeartbeatAck`, `StartStream`/`StopStream`.
2. Agent side: `agent/src/transport/mod.rs` + `agent/src/transport/websocket.rs` — confirm it
   encodes/decodes via prost (`encode_to_vec` / `Message::decode`) and handles every inbound
   variant it should. Any server→agent variant with no handler → dead/missing.
3. Server side: `server/src/relay/mod.rs` — confirm the relay decodes agent frames and forwards
   the right variants to viewers, and decodes viewer input and forwards to the agent. Any proto
   variant the relay never matches → dead code or missing relay path.
4. Dashboard side: `dashboard/src/lib/protobuf.ts` hardcoded message IDs + `types/protocol.ts`
   field names. **Cross-check the hardcoded IDs against the proto field numbers** and the TS field
   names against the proto field names. Mismatch → `[HIGH]` (silent frame/event corruption).

   Build the drift matrix: `message/field | proto | agent (prost) | server (prost) | dashboard (manual)`
   and flag every row that isn't consistent across all four.

**Migration integrity:**
- List `server/migrations/*.sql` — verify sequential numbering with no gaps (currently
  `001_initial_schema`, `002_user_management`, `003_auto_update`).
- For each `CREATE TABLE` (users, machines, sessions, support_codes, events, releases…), verify a
  corresponding `server/src/db/<name>.rs` module exists and its struct fields match the columns.

**Version consistency:**
- `agent/Cargo.toml`, `server/Cargo.toml`, `dashboard/package.json` versions — are they in sync?
  (All were `0.2.0` at last map.) The agent embeds version via `agent/build.rs` (CARGO_PKG_VERSION
  + git hash). Note divergence; there is **no automatic version bump yet** (SPEC-001 §3 pending) —
  so out-of-sync versions are a `[MEDIUM]` worth surfacing, not necessarily a bug.

**WebSocket frame validation:**
- In `server/src/relay/mod.rs`, are inbound frames size-capped before decode/relay? An unbounded
  `VideoFrame` from a hostile agent → server OOM. No cap → `[HIGH]` (see Agent E for the security
  framing).

Return structured findings with file:line references and the drift matrix.

---

### Agent E — Security & Remote-Session Integrity

**Goal:** GC is a remote-control product — the threat surface is session hijack, input injection,
and relay abuse. Verify the boundaries the SEC* audits established still hold and check the gaps
they flagged.

**Instructions for agent:**

Read the existing security audit docs first so you don't re-report settled items (note their
status and only re-flag if the code regressed): `SEC3_SQL_INJECTION_AUDIT.md`,
`SEC4_AGENT_VALIDATION_AUDIT.md` / `_COMPLETE.md`, `SEC5_SESSION_TAKEOVER_AUDIT.md` / `_COMPLETE.md`,
and `TECHNICAL_DEBT.md` security items.

**Session & auth boundaries:**
- Viewer WS auth: `viewer_ws_handler` validates a JWT (query param). Confirm the token is verified
  (signature + expiry + blacklist), not just parsed. A viewer joining a session must be authorized
  for *that* session, not any session.
- Agent WS auth: `agent_ws_handler` accepts `support_code` OR `api_key`. Confirm support codes are
  single-use and **revocation updates the in-memory store immediately** (a revoked code must fail
  even if the agent reconnects before a server restart — `server/src/db/support_codes.rs` /
  in-memory map).
- Session takeover: sessions keyed by UUID, heartbeat timeout ~90s. Confirm a new viewer cannot
  attach to or hijack an existing session without authorization, and that session IDs aren't
  guessable/loggable in a way that enables replay.

**Relay abuse / DoS:**
- Frame size caps on inbound WS messages (agent video frames AND viewer input) — unbounded →
  `[HIGH]` OOM/DoS vector.
- Input event injection: viewer→agent mouse/key events — is there rate limiting or a bounded queue
  on the agent input path (`agent/src/input/`)? Unbounded input spam → agent CPU/queue exhaustion.
- Rate limiting on auth endpoints (`server/src/middleware/rate_limit.rs`, `tower_governor`) — still
  applied to `/api/auth/login`? Confirm it's wired, not just present.

**Secrets & transport:**
- JWT secret, agent API key sourced from env (not hardcoded) and length-checked at startup.
- TLS/WSS required for relay; no plaintext fallback that carries frames or credentials.
- Passwords hashed with Argon2id (`server/src/auth/password.rs`).

Return structured findings with file:line references. Severity by impact (a session-hijack path is
`[CRITICAL]` even if the fix is small).

---

### Agent F — Docs & Roadmap Reconciliation

**Goal:** Make GC's living docs tell the truth. Reconcile every roadmap checkbox and debt item
against the actual code.

**Runs in parallel with A-E (read-only code search, no SSH).**

**Instructions for agent:**

1. Read `docs/FEATURE_ROADMAP.md` and extract every checkbox line with state (`[ ]`/`[~]`/`[x]`),
   section, and priority. Also read `TECHNICAL_DEBT.md` (repo root; items + the "Completed Items"
   section), **every** `docs/specs/SPEC-*.md` (Glob them — SPEC-001 §1-§6 deliverables, SPEC-002 v2
   architecture phases + decisions, and any later specs), and **every** `specs/*/plan.md` shape-spec
   (its task list + `[DONE]` markers).

2. For EACH item, find the implementing artifact in code — do NOT trust the checkbox:
   - API/endpoint features → `server/src/api/mod.rs` routes + handler module
   - Relay/session features → `server/src/relay/mod.rs`, `server/src/session/`
   - Protocol features → `proto/guruconnect.proto` + agent/server prost usage
   - Agent capabilities (capture, input, tray, update) → `agent/src/`
   - Dashboard/viewer features → `dashboard/src/components|hooks/*` + static HTML
   - CI/release deliverables (SPEC-001: versioning, signing, changelog API, gc-feature-request
     skill, coord-API) → `.gitea/workflows/*`, `scripts/*`, `.claude/commands/gc-feature-request.md`
   - **Shape-spec `plan.md` tasks** → find the implementing artifact for each task. A task marked
     `[DONE]` but not in code → **STALE-COMPLETE `[HIGH]`** (the plan is lying); implemented but not
     marked `[DONE]` → recommend adding the marker. **SPEC-002 phase deliverables** → reconcile each
     against code the same way (a phase claimed done that isn't, or shipped-but-unmarked).
   Use Grep/GrepAI. Cite the exact artifact (file:line, migration name, route path, workflow job).

3. Classify each item:
   - **STALE-INCOMPLETE** — `[ ]`/`[~]` but code fully implements it end-to-end → recommend `[x]`.
   - **PARTIAL** — `[ ]`/`[~]`, some layers exist but not end-to-end for the stated scope → keep
     `[ ]`/`[~]`, recommend an inline scope annotation. Do NOT flip to `[x]`.
   - **STALE-COMPLETE** — `[x]` but code does not implement it (never built / reverted) →
     recommend flip to `[ ]`, flag `[HIGH]` (the roadmap is lying).
   - **ACCURATE** — matches. No change.

4. For `TECHNICAL_DEBT.md`: identify debt items the code shows are now fixed → recommend moving them
   to the "Completed Items" section with a date. Identify items still open that the code confirms.

5. Be conservative: only flip `[ ]`→`[x]` when evidence is unambiguous AND end-to-end. When in
   doubt → PARTIAL with a note. Bias toward under-flipping.

Return three tables:
`roadmap item | section | current | verdict | proving-or-missing artifact`
`debt item | current status | verdict (fixed/open/partial) | artifact`
`spec/plan item (SPEC-NNN phase or specs/<slug> plan.md task) | claimed state | verdict (done / partial / not-started / [DONE]-but-missing) | artifact`

---

### Agent G — CI/CD Pipeline & Deploy Health

**Goal:** Verify the build/deploy infrastructure is functioning and the SPEC-001 quality gates are
in the state the docs claim. Catches issues invisible to codebase-only audits: broken workflows,
unregistered runners, stale deploys, gate drift.

**NOTE:** Runs sequentially (after A-F) because it SSHes the live deploy host and hits HTTP
endpoints. Read-only — checks state, never triggers a build or deploy.

**Instructions for agent:**

**1. Gitea Actions workflow integrity (read the repo files):**
- `.gitea/workflows/build-and-test.yml` — confirm jobs: `build-server` (fmt --check, clippy,
  build, test), `build-agent` (Windows MSVC on the Pluto runner, PROTOC + crt-static), and
  `security-audit` (`cargo audit`). Note whether clippy/audit are **informational** (warn-only) or
  **hard-fail** (`-D warnings` / fail-on-vuln).
- `.gitea/workflows/deploy.yml` — confirm trigger (tag `v*.*.*` / manual) and whether the actual
  SSH deploy step is real or still a stub (`echo "[INFO] SSH to 172.16.3.30…"`).
- `.gitea/workflows/release.yml` (if present) — SPEC-001 §2-§4: version bump, changelog gen,
  `jsign` + Azure Trusted Signing step. Note which deliverables are wired vs. pending.
- `bash -n` is not applicable to YAML; instead sanity-check each workflow for: valid `on:` triggers,
  every `uses:`/`run:` step present, no job referencing a secret that the audit notes as unset.

**SPEC-001 gate cross-check (ties to the active lint-debt work):** the SPEC-001 quality gates aim to
flip clippy to hard-fail + enforce `cargo audit`. Report the CURRENT enforced state vs. the SPEC-001
target so it's clear whether the tightening has landed. (~65 pre-spec clippy warnings were noted as
informational at last map — confirm count/state.)

**2. Gitea runner registration & health:**
- TECHNICAL_DEBT.md item #1 flagged runner registration as CRITICAL/blocking. Verify a runner is
  registered and online for both `ubuntu-latest` (server/audit jobs) and the Windows/Pluto runner
  (agent job). On the Gitea host or via the Gitea API, check the actions runner list. If no Windows
  runner is online → `[CRITICAL]` agent builds cannot run. Reference `.claude/machines/pluto.md` for
  the Pluto runner setup (PROTOC at `C:\protoc\bin\protoc.exe`, Administrator `.cargo`/`.rustup`).

**3. Deploy host health (`ssh guru@172.16.3.30`):**
```bash
systemctl status guruconnect.service --no-pager
curl -s -o /dev/null -w '%{http_code}' http://localhost:3002/health
curl -s http://localhost:3002/metrics | head -20
ls -lht /home/guru/guru-connect/server/migrations/
```
- `guruconnect.service` not `active (running)` → `[CRITICAL]`.
- `/health` non-200 / refused → `[CRITICAL]`.
- `/metrics` empty or refused → `[HIGH]` (Prometheus scrape broken).
- Confirm the binary on disk matches a recent commit:
  `cd /home/guru/guru-connect && git log --oneline -5` and compare to the running version
  (the service version vs. `git rev-parse HEAD`). Months-old running binary while git shows recent
  work → `[HIGH]` deploy stuck (consistent with the stubbed deploy step).
- Confirm migrations applied: query `_sqlx_migrations` (003 should be present). Missing → `[HIGH]`.

**4. Artifact distribution:**
- Agent download served at `https://connect.azcomputerguru.com/downloads/guruconnect.exe`
  (or the path configured in `server/src/api/downloads.rs`). Verify the file exists and its mtime is
  recent relative to agent commits. Stale/missing → `[HIGH]` (clients download an old agent).
- Confirm the served EXE is **signed** if SPEC-001 §2 signing has landed; unsigned while signing is
  marked done → `[HIGH]`.

**5. Monitoring stack (per INFRASTRUCTURE_STATUS.md):**
- Prometheus scraping GC `/metrics`; Grafana dashboard reachable. Backup timer
  (`guruconnect-backup.timer`) enabled: `systemctl status guruconnect-backup.timer --no-pager`.
  Disabled/failed backup timer → `[MEDIUM]`.

Return structured findings with source (file path + line, or command + output) for every finding.

---

## Phase 3: Aggregating Findings

Collect all agents' outputs. Classify each finding:

| Severity | Meaning |
|----------|---------|
| `[CRITICAL]` | Security vuln (session hijack, auth bypass), data loss, production crash, or broken-build/deploy blocker |
| `[HIGH]` | Functional gap blocking a core workflow, protocol drift causing silent corruption, or standards violation with user impact |
| `[MEDIUM]` | Code quality issue, version skew, or inconsistency without immediate impact |
| `[LOW]` | Minor polish, dead code, missing comment |
| `[INFO]` | Neutral observation, completed item, or context note |

Deduplicate: if two agents flag the same issue from different angles (e.g. Agent C on the TS
decoder and Agent D on the proto side of the same field), merge into one finding with both
references.

---

## Phase 4: Write Report + Update Living Docs

### Report Location

Write to: `projects/msp-tools/guru-connect/reports/YYYY-MM-DD-gc-audit.md` (use the actual date).
**The `reports/` directory does not exist yet — create it on first run.** If a report from today
already exists, append a `-2` suffix.

### Report Format

```markdown
# GuruConnect Audit Report — YYYY-MM-DD

**Auditor:** Claude (<model id>)
**Passes:** API Surface, Rust Quality, TypeScript/Dashboard, Protocol Integrity, Security & Session, Docs Reconciliation, CI/CD Pipeline
**Previous audit:** [link to prior report if one exists, else "First audit"]

---

## Executive Summary

| Pass | Total | Critical | High | Medium | Low |
|------|-------|---------|------|--------|-----|
| API Surface | N | N | N | N | N |
| Rust Quality | N | N | N | N | N |
| TypeScript/Dashboard | N | N | N | N | N |
| Protocol Integrity | N | N | N | N | N |
| Security & Session | N | N | N | N | N |
| CI/CD Pipeline | N | N | N | N | N |
| **TOTAL** | **N** | **N** | **N** | **N** | **N** |

**Requires immediate action:** [one line per CRITICAL finding]

---

## Pass 1: API Surface
### [SEVERITY] Finding Title
**File:** path:LINE
**Detail:** What the problem is, why it matters.
**Recommendation:** What to do.
[repeat per finding]

---
## Pass 2: Rust Code Quality
## Pass 3: TypeScript / Dashboard Quality
## Pass 4: Protocol & Wire-Format Integrity
[include the 4-way drift matrix]
## Pass 5: Security & Remote-Session Integrity
## Pass 6: CI/CD Pipeline Health
[Gitea Actions workflow state, runner registration, gate state vs SPEC-001 target, deploy host, artifact freshness]

---

## FEATURE_ROADMAP.md Delta (Agent F)
Checkboxes corrected to match code reality this audit:
- `[ ]`/`[~]` → `[x]` **<item>** — shipped. Proof: `<artifact>`.
- `[x]` → `[ ]` **<item>** — marked complete but NOT in code (regression / never built). `[HIGH]`
Annotated as partial (scope clarified): - `[ ]` **<item>** (<scope note>) — `<artifact>`
Verified accurate (no change): N items.

## TECHNICAL_DEBT.md Delta (Agent F)
Items moved to "Completed Items": - **<item>** — fixed. Proof: `<artifact>`.
Still open (confirmed): N items.

---

## Recommended Action Order
1. [CRITICAL items, sorted by impact]
2. [HIGH items]
3. [MEDIUM items — can be batched]
```

### Update Living Docs

After writing the report, apply Agent F's reconciliation (this is the cleanup the audit owns;
editing living docs fits the "living docs are updated" exception to read-only):

- **`docs/FEATURE_ROADMAP.md`** — default is reconcile-and-flip:
  - STALE-INCOMPLETE → flip `[ ]`/`[~]` to `[x]` for every item proven shipped end-to-end; optionally
    append `(verified <date>)`.
  - PARTIAL → leave the box, append the scope annotation. Never flip a partial to `[x]`.
  - STALE-COMPLETE → flip `[x]` to `[ ]`, add `[REGRESSION — flagged YYYY-MM-DD]`, mirror as a
    `[HIGH]` finding in the report.
- **`TECHNICAL_DEBT.md`** — move confirmed-fixed items into the "Completed Items" section with a date;
  leave open items in place.
- Every doc change MUST also appear in the report's Delta section with its proving artifact — no
  silent edits. When evidence is ambiguous, do NOT change the doc; record as PARTIAL/INFO for human
  review. Bias toward under-flipping.

---

## Phase 5: User Summary

Present a concise summary to the user:

```
Audit complete. Report: projects/msp-tools/guru-connect/reports/YYYY-MM-DD-gc-audit.md

CRITICAL (N): [one-line each]
HIGH (N):     [one-line each]
MEDIUM (N):   Batched in report.

Protocol drift: [one-line — e.g. "proto/agent/server/dashboard consistent" or the worst mismatch]
Pipeline: [one-line — e.g. "all green" or highest-severity finding; note clippy/audit gate state vs SPEC-001]
Roadmap: N checkboxes corrected (N stale-incomplete flipped, N partial annotated, N regressions flagged).
Tech debt: N items moved to Completed.

Recommended first action: [the single highest-priority finding]
```

Then ask: "Want me to start on any of these findings?"

---

## Conventions

- **Read, don't run.** Never executes production code or triggers builds/deploys. Reads files,
  uses Grep/GrepAI, and (Agent G only) runs read-only status/HTTP checks.
- **Derive from code, not docs.** Treat all `.md`/`.json` status docs as potentially stale. Code is
  truth. (The whole point of Agent F.)
- **Be specific.** Every finding needs a file:line reference. Vague findings are useless.
- **No false positives.** If something looks wrong but context makes it acceptable, note it `[INFO]`
  with the reason. (Especially: `sqlx::query!` macros are fine here; informational clippy/audit gates
  are a known SPEC-001 state, not a bug — report the state, don't cry wolf.)
- **Severity is impact, not effort.** A two-line fix can be `[CRITICAL]` if it's a session-hijack path.
- **Commit the report.** After writing, delegate to the Gitea Agent to commit the report file and the
  living-doc updates to the `guru-connect` repo (not any code fixes — those are separate work items).
  Respect any active coord lock on `guruconnect` before editing `.gitea/workflows` or docs.

---

## Reference: Key Files by Area

### Server (`server/src/`)
| Area | Key Files |
|------|-----------|
| Routes | `api/mod.rs` (+ `main.rs` registration), submodules `api/{auth,users,downloads,releases,changelog}.rs` |
| WebSocket relay | `relay/mod.rs` (`agent_ws_handler`, `viewer_ws_handler`) |
| Sessions | `session/mod.rs` |
| DB layer | `db/mod.rs`, `db/{users,machines,sessions,events,support_codes,releases}.rs` |
| Migrations | `migrations/00{1,2,3}_*.sql` |
| Auth | `auth/{jwt,token_blacklist,password,mod}.rs` |
| Rate limiting | `middleware/rate_limit.rs` |
| Generated proto | `OUT_DIR` via `server/build.rs` (do not audit generated code) |

### Agent (`agent/src/`)
| Area | Key Files |
|------|-----------|
| Transport / wire | `transport/mod.rs`, `transport/websocket.rs` |
| Capture | screen/DXGI-GDI capture modules |
| Input injection | `input/` |
| Version embed | `agent/build.rs` |

### Dashboard (`dashboard/src/`)
| Area | Key Files |
|------|-----------|
| Viewer component | `components/RemoteViewer.tsx`, `components/SessionControls.tsx` |
| Session hook | `hooks/useRemoteSession.ts` |
| Manual protobuf | `lib/protobuf.ts` (hardcoded message IDs — drift hazard) |
| Protocol types | `types/protocol.ts` |
| Served static UI | `server/static/{login,dashboard,viewer}.html` |

### Protocol
| Area | Path |
|------|------|
| Proto definition | `proto/guruconnect.proto` |

### CI/CD & Infra
| Area | Path |
|------|------|
| CI gate | `.gitea/workflows/build-and-test.yml` |
| Deploy | `.gitea/workflows/deploy.yml` |
| Release/signing | `.gitea/workflows/release.yml`, SPEC-001 |
| Runner setup | `scripts/install-gitea-runner.sh`, `.claude/machines/pluto.md` |
| Deploy host | 172.16.3.30:3002, systemd `guruconnect.service` |
| Monitoring | `infrastructure/{prometheus.yml,grafana-dashboard.json,alerts.yml}`, `guruconnect-backup.timer` |

### Docs / Standards
| Area | Path |
|------|------|
| GC instructions/standards | `CLAUDE.md` |
| Shared coding standards | `.claude/CODING_GUIDELINES.md` (monorepo root) |
| Feature roadmap | `docs/FEATURE_ROADMAP.md` |
| Tech debt backlog | `TECHNICAL_DEBT.md` (repo root) |
| Architecture decisions | `docs/ARCHITECTURE_DECISIONS.md` (ADR-001 RMM↔GC contract, ADR-002 release eng) |
| Architecture/feature specs | `docs/specs/SPEC-*.md` (SPEC-001 release-eng, SPEC-002 v2 architecture, …) |
| Shape-spec plans | `specs/*/{plan,shape,references,standards}.md` (e.g. `v2-secure-session-core`, `native-remote-control`) — `plan.md` `[DONE]` markers are a reconciliation target |
| Granular standards (compliance baseline) | `.claude/standards/index.yml` + `.claude/standards/**/*.md` |
| Changelogs (SPEC-001 changelog API) | `changelogs/LATEST_{SERVER,AGENT,DASHBOARD}.md`, `changelogs/<component>/v*.md`, `CHANGELOG.md` |
| Security audits | `SEC{3,4,5}_*_AUDIT.md` / `_COMPLETE.md` |
| Past audit reports | `reports/` (create on first run) |
