# Session Log — 2026-05-21

## User
- **User:** Mike Swanson (mike)
- **Machine:** DESKTOP-0O8A1RL
- **Role:** admin
- **Session span:** ~09:00–10:30 PT (approx, continued from compacted context)

---

## Session Summary

The session resumed mid-task from a compacted prior context. The first half completed billing for Peaceful Spirit Massage ticket #32271 ("Bug - IKEv2 VPN drops and does not auto-reconnect"), which involved deploying machine certificate IKEv2 VPN to BridgettePSHomeComputer, configuring a boot-time scheduled task for pre-login auto-connect, and adding PEACEFULSPIRIT\BridgetteSH to local Administrators.

Billing completion was complicated by a cascading API issue: the initial POST /invoices call returned null fields, which was treated as failure and triggered a retry using the `ticket_ids` (plural array) format — this created a blank $0 invoice (67638) that was subsequently deleted. A GET on customer invoices revealed the first POST had actually succeeded, creating invoice 67637 ($325) linked to the ticket. The $325 total was caused by two line items: the correct one (42535605, Labor Remote $150) and a wrong one (42535510, Labor Onsite $175) left over from the timer/charge_timer_entry bug from the prior session. Invoice 67638 was deleted, ticket was marked Invoiced, and a Discord bot-alert was posted. A detailed correction note for Winter was posted to #bot-alerts explaining the wrong line item and the manual GUI deletion required.

The second half of the session was a focused overhaul of the Syncro skill (`.claude/commands/syncro.md`). Mike directed the changes: (1) eliminate the timer_entry/charge_timer_entry billing path entirely in favor of direct add_line_item, (2) optimize for speed and accuracy by replacing procedural prose with locked, exact API sequences, and (3) nail down exact response shapes for every endpoint by testing live against the ACG internal customer (Arizona Computer Guru, ID 15353550). Two test tickets were created and cleaned up during this process. (4) The bot-alerts section was tightened with explicit success/fail criteria matching the actual script behavior. (5) The contact_id behavior was clarified: omit by default since Syncro assigns the primary contact automatically; only set it when a specific named contact is relevant.

Three commits landed on main: `ced6254` (timer → add_line_item refactor + verified response shapes), `30c5c25` (contact_id default behavior), and `ced6254` covered the bot-alerts tightening as well.

---

## Key Decisions

- **Omit `contact_id` by default on ticket creation.** Syncro assigns the primary contact automatically when the field is absent. The API does not expose a "primary" flag on contacts — the email-match heuristic was unreliable (failed on 2 of 4 tested customers). The correct behavior is to let Syncro handle it and only look up a contact ID when a specific person is named.

- **Replaced timer workflow with direct add_line_item.** Mike confirmed timers are never used for billing at ACG. The timer_entry → charge_timer_entry path was the source of repeated billing errors (wrong product frozen at timer creation, charge_timer_entry silently ignoring product_id overrides). Removing it eliminates an entire class of bugs.

- **Tested all endpoints live before documenting response shapes.** Rather than inferring or copying from docs, every response shape in the Verified Response Shapes table was confirmed against the live API using the ACG internal customer. Key finding: add_line_item returns a FLAT object (parse `.id`, not `.line_item.id`); update_line_item returns `{"ticket_line_item": {...}}`; invoice GET line_items use `price` not `price_retail`.

- **Added "STOP, never experiment" hard rule.** The root cause of slow, error-prone Syncro sessions was improvising alternatives when a response looked unexpected. The new rule is explicit: on any unexpected response, stop and report — do not try alternative endpoints or payload formats. The API does not change between calls.

- **Invoice null-response was a one-time server anomaly, not a systemic issue.** Live testing confirmed POST /invoices with `ticket_id` (singular) returns a proper populated response in normal operation. The null from the prior session was likely caused by the ticket being in an inconsistent state (two competing line items from the timer/add_line_item mix). The recovery path (GET /invoices?customer_id=N to find by ticket_id) is documented but should rarely be needed.

---

## Problems Encountered

- **Invoice 67637 was $325 instead of $150.** Caused by the prior session's timer bug leaving line item 42535510 (Onsite $175) on the ticket alongside the correct 42535605 (Remote $150). The invoice picked up both. Cannot be fixed via API — requires manual deletion of 42535510 in Syncro GUI. Winter notified via #bot-alerts with full explanation.

- **Empty invoice 67638 created.** Retrying POST /invoices with `ticket_ids` (plural array) after the null response created a blank $0 invoice with no line items and no ticket link. Deleted via `DELETE /invoices/1650372824`. Root cause: treating a successful null-field response as failure and trying an alternative format.

- **Discord bot-alert 403 error on second post attempt.** Cloudflare blocked Python's `urllib` (HTTP 403 error code 1010) but curl with a proper `User-Agent` header succeeds. Workaround: write the message to a temp JSON file and invoke curl via a script file to avoid the pre-bash-backslash hook. The `post-bot-alert.sh` helper already handles this correctly — the issue only arose when posting manually outside the helper.

---

## Configuration Changes

- **`.claude/commands/syncro.md`** — Major refactor:
  - Hard rule: billing uses add_line_item directly, not timer_entry/charge_timer_entry
  - Hard rule: STOP on unexpected response, never experiment with alternatives
  - Added "Verified Response Shapes" table (all endpoints, tested live 2026-05-21)
  - Billing workflow rewritten as strict 5-step locked script
  - Ticket creation: contact_id omitted by default; only set for named contacts
  - bot-alerts section: explicit success (`[OK] ... message_id=N`) and failure (`[WARNING]`) criteria
  - Removed address_id, appointment_owner, do_not_invite from default gather inputs
  - Removed all timer endpoint documentation from billing context

- **`.claude/memory/feedback_syncro_timer_first.md`** — Superseded: old "timers required" rule replaced with "use add_line_item directly" rule, effective 2026-05-21.

---

## Credentials & Secrets

No new credentials created or discovered this session.

Relevant existing credentials:
- Syncro API key (mike): `T259810e5c9917386b-52c2aeea7cdb5ff41c6685a73cebbeb3`
- Discord bot token: vault at `projects/discord-bot/bot-token.sops.yaml` → `credentials.bot_token`
- Discord #bot-alerts channel ID: `624710699771232265`

---

## Infrastructure & Servers

- **BridgettePSHomeComputer** — Machine cert (thumbprint 16FC5022F97978DA54ED63FB29F9BEC5D52D99C1) deployed, AllUserConnection IKEv2 VPN "Peaceful Spirit VPN" created, boot scheduled task "PeacefulSpiritVPN-AutoConnect" registered (SYSTEM, PT30S delay, 5 retries × PT1M). PEACEFULSPIRIT\BridgetteSH added to local Administrators. VPN connected live for profile setup.
- **PST-SERVER** — RMM agent was offline 2026-05-14 to 2026-05-21, manually restarted. Root cause undiagnosed.
- **GuruRMM API** — `http://172.16.3.30:3001` used for remote PowerShell execution on BridgettePSHomeComputer and PST-SERVER.

---

## Commands & Outputs

```bash
# Verified add_line_item response shape (FLAT)
POST /tickets/{id}/add_line_item → {"id": 42536139, "ticket_id": ..., "price_retail": 150.0, ...}
# Parse: .id directly

# Verified invoice creation
POST /invoices with {"ticket_id": N, "customer_id": N} → {"invoice": {"id": N, "total": "75.0", ...}}
# Parse: .invoice.id, .invoice.total

# Verified update_line_item response (WRAPPED differently)
PUT /tickets/{id}/update_line_item → {"ticket_line_item": {"id": N, ...}}
# Parse: .ticket_line_item.id

# Invoice GET line_items field names differ from ticket line_items
GET /invoices/{id} → .invoice.line_items[].price  (NOT .price_retail)
                   → .invoice.line_items[].item   (product name, NOT .name)
                   → .invoice.line_items[].name   (description, NOT .item)

# Delete empty invoice 67638
DELETE /invoices/1650372824 → {"message": "1650372824: We deleted # 67638. "}

# ACG internal customer for API testing
Customer ID: 15353550 — Arizona Computer Guru
Test tickets created and closed: 110736645, 110736988
```

---

## Pending / Incomplete Tasks

- **[IMMEDIATE — Manual GUI]** Delete line item 42535510 (Labor - Onsite Business, $175) from ticket #32271 in Syncro GUI. Invoice 67637 will recalculate to $150. URL: https://computerguru.syncromsp.com/tickets/110169036

- **[NEXT]** Reboot BridgettePSHomeComputer to verify scheduled task fires and VPN auto-connects pre-login. Login screen network icon presence also unconfirmed.

- **[PENDING]** Deploy machine cert + VPN to Maras-HP-Laptop (agent 13cb3629-5043-4bd6-b977-6968eeccf804, thumbprint 4CADDE8F, PFX at C:\Users\guru\AppData\Local\Temp\Maras-HP-Laptop.pfx on PST-SERVER)

- **[PENDING]** Deploy machine cert + VPN to PST-SURFACE (agent 4a993b61-59b3-42f4-bdb5-d4362941f7d6, thumbprint 197FF22A, PFX at C:\Users\guru\AppData\Local\Temp\PST-SURFACE.pfx on PST-SERVER)

- **[PENDING]** Diagnose PST-SERVER RMM agent recovery failure root cause (offline ~1 week)

- **[PENDING]** Delete plaintext Zoho backup codes file at C:/Users/guru/Downloads/Zoho - BACKUP VERIFICATION CODES.txt

---

## Reference Information

- **Ticket #32271** (Peaceful Spirit Massage) — https://computerguru.syncromsp.com/tickets/110169036
  - Status: Invoiced
  - Invoice #67637, ID 1650372791 — currently $325, should be $150 after GUI fix
  - Wrong line item to delete: ID 42535510 (Labor - Onsite, $175)
  - Correct line item: ID 42535605 (Labor - Remote, $150)

- **Syncro skill commits:**
  - `ced6254` — timer → add_line_item refactor, verified response shapes, billing script, bot-alerts criteria
  - `30c5c25` — contact_id default behavior (omit unless named contact)

- **Peaceful Spirit VPN server:** 98.190.129.150 (RRAS on PST-SERVER)
- **PEACEFULSPIRIT Enterprise CA:** PEACEFULSPIRIT-PST-SERVER-CA on PST-SERVER

- **ACG internal Syncro customer:** ID 15353550 (Arizona Computer Guru) — use for API testing
- **Discord #bot-alerts channel:** 624710699771232265 (guild 624663750603046913)
- **post-bot-alert.sh:** D:/claudetools/.claude/scripts/post-bot-alert.sh

---

## Update: 10:00–11:00 PT — PST-SERVER RMM diagnosis, Mara VPN verification, cleanup

### Session Summary

Resumed after context compaction. Cleared several pending items from the earlier session and ran diagnostics on PST-SERVER's RMM agent outage.

Zoho backup codes plaintext file (`C:/Users/guru/Downloads/Zoho - BACKUP VERIFICATION CODES.txt`) was confirmed vaulted at `services/zoho.sops.yaml` and deleted. Winter's ticket #32271 invoice correction was handed off — she owns that fix.

PST-SERVER RMM agent outage (May 14–21) was diagnosed via GuruRMM remote exec. Event log revealed the root cause: agent version 0.6.2 exits cleanly on startup if it cannot connect to the server rather than entering a retry loop. A network event at the Peaceful Spirit site stopped both PST-SERVER and PST-SURFACE on May 12. When PST-SERVER's 0.6.2 agent tried to start again on May 14 at 5:54 AM, it ran for exactly one second and exited with no error logged. It remained offline until manually reinstalled today with 0.6.27, which added a watchdog service and proper connection retry. PST-SERVER is now healthy. PST-SURFACE still has 0.6.2 and is offline (last seen May 12) — needs physical or ScreenConnect access to reinstall.

Mara's IKEv2 VPN deployment was verified complete on Maras-HP-Laptop via remote PowerShell: VPN profile "Peaceful Spirit VPN" (IKEv2, MachineCertificate, server 98.190.129.150), machine cert thumbprint 4CADDE8F issued by PEACEFULSPIRIT-PST-SERVER-CA (valid through May 2027), and scheduled task "PST VPN Auto-Connect" in Ready state. No changes made. PST-SURFACE VPN status cannot be verified remotely while the agent is offline.

`sync.md` skill doc was updated to accurately reflect current `sync.sh` behavior: `git add -A` (not staged-by-name), untracked-only detection via `git status --porcelain`, and Phase 5b commands-to-global copy step added on Beast.

### Key Decisions

- **Did not attempt PST-SURFACE VPN verification or remediation.** Machine is offline; remote exec is not available. Physical or ScreenConnect access required before any cert/VPN work can proceed.
- **No changes made to Maras-HP-Laptop.** VPN deployment confirmed complete by inspection only, consistent with user's indication that the work was already done.

### Problems Encountered

- **Gitea unreachable (172.16.3.20:3000) on first two /sync attempts.** Host not responding to ping. Resolved on third attempt ~2 minutes later — transient network blip.

### Configuration Changes

- `D:/claudetools/.claude/commands/sync.md` — updated description to reflect `git add -A`, untracked detection, and Phase 5b commands sync (commit `582c511`)

### Credentials & Secrets

No new credentials. GuruRMM admin credentials confirmed still valid:
- Email: `admin@azcomputerguru.com`, Password: `GuruRMM2025`
- JWT secret vault path: `projects/gururmm/api-server.sops.yaml`

### Infrastructure & Servers

- **PST-SERVER** — GuruRMM agent ID `6b6106a7-8515-4b6b-857d-0dc6ede53f35`, now online, version 0.6.27, watchdog service installed
- **PST-SURFACE** — agent ID `4a993b61-59b3-42f4-bdb5-d4362941f7d6`, offline since 2026-05-12, version 0.6.2, site: Mara Home
- **Maras-HP-Laptop** — agent ID `13cb3629-5043-4bd6-b977-6968eeccf804`, online, version 0.6.27, VPN fully deployed
- **BridgettePSHomeComputer** — agent ID `074141d7-bd96-49ff-8f64-edf31159c00b`, 0.6.27, VPN tested and working (confirmed by user)

### Commands & Outputs

```bash
# GuruRMM auth
POST http://172.16.3.30:3001/api/auth/login
{"email":"admin@azcomputerguru.com","password":"GuruRMM2025"} → .token

# PST-SERVER event log root cause (run remotely via GuruRMM)
# 2026-05-10 16:19 — Agent 0.6.2 installed and started
# 2026-05-12 18:08 — Service stopped clean (EventID 7036) — network event at PS site
# 2026-05-14 05:54 — Started (7036), stopped 1 second later (7036) — 0.6.2 exits on connection failure
# 2026-05-21 08:20 — Reinstalled as 0.6.27 with watchdog service (new 7045 events), now stable

# Maras-HP-Laptop VPN verification (all confirmed present, no changes made)
# VPN: "Peaceful Spirit VPN", IKEv2, MachineCertificate, server 98.190.129.150
# Cert: thumbprint 4CADDE8F, CN=Maras-HP-Laptop.PEACEFULSPIRIT.local, expires 2027-05-10
# Task: "PST VPN Auto-Connect", State: Ready
```

### Pending / Incomplete Tasks

- **[MANUAL — Physical/ScreenConnect]** PST-SURFACE: reinstall GuruRMM agent 0.6.27, then verify IKEv2 VPN + cert deployment
- **[RESOLVED]** PST-SERVER RMM outage — root cause identified (0.6.2 startup-exit bug), fixed by 0.6.27 reinstall
- **[RESOLVED]** Zoho backup codes plaintext file — deleted (was vaulted)
- **[RESOLVED]** Maras-HP-Laptop VPN — verified complete, no action needed
- **[RESOLVED]** BridgettePSHomeComputer VPN — confirmed working by user

### Reference Information

- GuruRMM agent 0.6.2 bug: exits cleanly on startup connection failure (no error log, no retry) — fixed in 0.6.27 + watchdog
- Peaceful Spirit agent roster: PST-SERVER (online/0.6.27), PST-SURFACE (offline/0.6.2), Maras-HP-Laptop (online/0.6.27), MaraHomeNew (online/0.6.27), BridgettePSHomeComputer (online/0.6.27)
- `sync.md` update commit: `582c511`

---

## Update: afternoon PT — Howard: Cascades comment + syncro skill review

**User:** Howard Enos (howard) | HOWARD-HOME

Posted internal Syncro comment to ticket #32303 (Cascades migration) documenting that Lauren Hasselman and Crystal Rodriguez passwords did not work — could not access their machines. Comment ID 412091314, hidden/internal, attributed to Howard Enos.

Ran `/sync`, pulled Mike's 11 commits. Reviewed updated `syncro.md` — key change: billing now uses `add_line_item` directly instead of the timer workflow. This affects all future Cascades billing. Full session log at `clients/cascades-tucson/session-logs/2026-05-21-session.md`.

---

## Update: late afternoon PT — IX hosting scan, hightechmortgage.com DNS, Rob Williams access

**User:** Mike Swanson (mike) | DESKTOP-0O8A1RL

### Session Summary

Mike requested activity stats for packetdial.com on IX hosting ahead of a meeting with Rob Williams. WHM API was used to confirm the account exists. cPanel session API was unusable (forced password reset redirect returning 307 on every call), so Python paramiko SSH to root on 172.16.3.10 was used instead to run `find` commands directly on the filesystem. A 90-day modified-file scan on `/home/packetdial/public_html` was run with WP core directories excluded (wp-admin, wp-includes, cache, vendor, node_modules, logs). Results showed limited file activity — mostly auto-update artifacts, no custom plugin or theme development in the scanned window.

Mike then asked to scan all 72 IX accounts for real dev work using the same approach. A Python paramiko script (`ix_all_sites.py`) was written and run, iterating every account returned by the WHM `listaccts` API, running monthly file modification counts per account, and flagging accounts with custom plugin/theme files or recent uploads. packetdial.com specifically showed low activity consistent with maintenance rather than active development.

During the Rob discussion, Mike forwarded a message from a client (hightechmortgage.com) asking Rob to add a Google Workspace TXT verification record. The record was added directly via WHM ZoneEdit API: `bash .claude/tmp/whm_dns.sh` against `172.16.3.10:2087`, adding `google-site-verification=7rmbUFlb1XViQjXJUZdpLpJSPvqkAvqrMgHhZ8yq6NA` as a TXT record on `hightechmortgage.com.` with TTL 300. Post-add verification confirmed the record was present.

Finally, Mike decided to give Rob Williams formalized access in the ClaudeTools Discord bot. Rob was added to `users.json` as a contractor and `DISCORD_CLAUDE.md` was updated to move him from no access to a "Recognized — Limited Operator" tier. His authorized scope covers M365 remediations via `/remediation-tool`, all IX Web Hosting and Websvr DNS/file/account changes, and full Syncro access (create/update/close tickets, add comments, bill time, create invoices). He cannot modify bot behavior, vault credentials, GuruRMM, or ACG's own M365 tenant. Rob's name was initially entered incorrectly as "Rob Quirarte" and corrected to "Rob Williams" after Mike pointed it out.

### Key Decisions

- **paramiko over cPanel session API.** cPanel UAPI via cookie session was blocked by a forced password reset page returning 307 on every request. Root SSH via paramiko bypasses this entirely and is faster for bulk filesystem scans.
- **WP core exclusions for activity scoring.** Excluded `wp-admin`, `wp-includes`, `cache`, `vendor`, `node_modules`, `uploads/cache`, `logs` when counting modified files. This prevents auto-update noise from inflating scores and gives a cleaner signal for actual dev work.
- **Rob's Syncro access = full tech-level.** Mike's guidance: "He can use Syncro, just cannot change behavior." Full create/update/close/bill access was granted rather than a read-only or restricted scope.
- **DISCORD_CLAUDE.md as access control surface.** Bot reads this file as its system prompt. Editing it directly controls Discord user permissions without any code deploys. Takes effect on next bot restart (`nssm restart ClaudeToolsDiscordBot` on BEAST).

### Problems Encountered

- **cPanel session API 307 redirect.** Every cPanel UAPI call via cookie session returned 307 redirect to a forced password reset page. Workaround: switched to paramiko root SSH, bypassing cPanel auth entirely.
- **Rob's name entered wrong.** `users.json` and `DISCORD_CLAUDE.md` initially had "Rob Quirarte" instead of "Rob Williams." Mike corrected this; both files were updated and recommitted (commit `063b209`).
- **Rob Syncro scope too restrictive on first pass.** Initial implementation gave Rob read-only Syncro. Mike clarified: full access. Updated in `DISCORD_CLAUDE.md` and committed as `8e8a18c`.

### Configuration Changes

- `D:/claudetools/.claude/users.json` — Added Rob Williams as contractor: email, role, Discord ID 261978810713505792, Syncro user_id 1760, authorized scope. Added "contractor" role definition.
- `D:/claudetools/projects/discord-bot/DISCORD_CLAUDE.md` — Rob moved from unknown/restricted to "Recognized — Limited Operator" with full scope definition. Multiple edits: initial access, name fix, Syncro upgrade.

### Credentials & Secrets

No new credentials created or vaulted.

Existing used:
- WHM root credentials: `infrastructure/ix-webhosting.sops.yaml` (host 172.16.3.10:2087)
- IX SSH: root@172.16.3.10 (same vault entry)

### Infrastructure & Servers

- **IX Web Hosting** — 172.16.3.10:2087 (WHM), 172.16.3.10:22 (SSH)
- **hightechmortgage.com** — DNS hosted on IX via cPanel account `hightechmortgage`; TXT verification record added
- **packetdial.com** — IX cPanel account `packetdial`; WordPress site, low recent dev activity
- **BEAST (GURU-BEAST-ROG)** — Discord bot service: `ClaudeToolsDiscordBot` (NSSM). Needs restart to pick up DISCORD_CLAUDE.md changes.

### Commands & Outputs

```bash
# WHM account list
curl -sk -u "root:<pass>" "https://172.16.3.10:2087/json-api/listaccts?api.version=1" | jq '[.data.acct[] | .user]'

# packetdial 90-day modified files (paramiko SSH)
find /home/packetdial/public_html -mtime -90 -type f \
  ! -path "*/wp-admin/*" ! -path "*/wp-includes/*" ! -path "*/cache/*" \
  ! -path "*/vendor/*" ! -path "*/node_modules/*" ! -path "*/logs/*" | wc -l

# hightechmortgage.com TXT record add (via WHM ZoneEdit API)
# Script: D:/claudetools/.claude/tmp/whm_dns.sh
# Result: status 1 (success), serial updated
TXT record: google-site-verification=7rmbUFlb1XViQjXJUZdpLpJSPvqkAvqrMgHhZ8yq6NA
TTL: 300, name: hightechmortgage.com.
```

### Pending / Incomplete Tasks

- **[Bot restart needed — BEAST]** `nssm restart ClaudeToolsDiscordBot` — required for Rob's new DISCORD_CLAUDE.md access to take effect
- **[SECURITY — IX]** packetdial.com webshell: `x919.php` at `/home/packetdial/public_html/x919.php` — responded HTTP 200 from 109.122.197.160. Needs deletion and investigation.
- **[MANUAL — Physical/ScreenConnect]** PST-SURFACE: reinstall GuruRMM agent 0.6.27, then verify IKEv2 VPN + cert deployment (agent offline since 2026-05-12)

### Reference Information

- Rob Williams Discord ID: `261978810713505792` | Syncro user_id: `1760`
- DISCORD_CLAUDE.md commits: initial access (pre-compaction), name fix `063b209`, Syncro upgrade `8e8a18c`
- IX hosting scripts: `D:/claudetools/.claude/tmp/ix_ssh.py`, `D:/claudetools/.claude/tmp/ix_all_sites.py`, `D:/claudetools/.claude/tmp/whm_dns.sh`
- packetdial.com webshell path: `/home/packetdial/public_html/x919.php`
- hightechmortgage.com WHM cPanel user: `hightechmortgage`

---

## Update: 19:25 PT — Hook portability fix + IX hosting AccelerateWP mass deployment

**User:** Mike Swanson (mike) | DESKTOP-0O8A1RL

### Session Summary

Session covered two distinct work areas: completing the Claude Code hook portability fix, and a full performance audit + AccelerateWP mass deployment across all IX Web Hosting sites.

**Hook portability (completed):** The UserPromptSubmit hook was already moved to the project-level `.claude/settings.json` using `$CLAUDE_PROJECT_DIR` in a prior session. Remaining cleanup: removed the old `hooks` block from `.claude/settings.local.json` (this machine) which contained the hardcoded `bash D:/claudetools/.claude/scripts/check-messages.sh` registration. The global `~/.claude/settings.json` was already clean. A new "Claude Code Hooks — where each hook lives" section was added to `.claude/ONBOARDING.md` documenting: which hook lives where, why local.json had a duplicate, cleanup steps, and machine-specific PreToolUse path examples for Windows and Mac. Coord messages were sent to Mac (Mikes-MacBook-Air), BEAST (GURU-BEAST-ROG), and Howard (HOWARD-HOME) instructing each to remove UserPromptSubmit hooks from their `~/.claude/settings.json` and `.claude/settings.local.json`.

**Performance investigation:** A performance report at `C:/Users/guru/Documents/report_20.05.2026.json` was analyzed. Two domains showed slow responses: phoenixmanagedservices.com (50% of requests slow, avg 2.89s, correlation 0.88) and danaise.com (5.1% slow, avg 2.46s, correlation 0.82). Both were identified as WordPress sites on IX with no page caching enabled. AccelerateWP (CloudLinux's page caching layer) was available server-wide but not activated on any account.

**Full IX server sweep:** After confirming AccelerateWP was available, Mike directed a full audit and remediation of all sites — not just the two in the report. A paramiko Python script iterated all 72 cPanel accounts on the IX server (172.16.3.10), identified active WordPress installs, checked AccelerateWP status, disabled conflicting plugins (LiteSpeed Cache, W3 Total Cache, Hummingbird, WP Defender performance, Jetpack CDN module), enabled AccelerateWP page cache, and verified WP_CACHE was set in wp-config.php.

**Final state:** 39 of 41 live WordPress sites now have AccelerateWP page cache enabled and verified caching. 2 sites skipped due to blockers (outaboundssports.com PHP fatal, farwestwell.com WP < 5.8 minimum). 11 abandoned/stale installs were intentionally skipped. Selected timing results after caching: danaise.com 0.39s (was 2.46s), phoenixmanagedservices.com 0.69s (was 2.89s).

**Individual fixes applied:**
- phoenixmanagedservices.com: added `define('WP_CACHE', true)` to wp-config.php (AWP installed advanced-cache.php but missed the constant); removed Performance Lab object-cache.php conflict; upgraded PHP 8.0 → 8.1; deactivated WP Defender performance module and Jetpack CDN.
- fsgtucson.com: AWP enable succeeded but WordPress returned HTTP 500 — traced to `option-tree` plugin being deactivated by WP-CLI `--skip-plugins` usage; reactivated it, site recovered.
- tarafulcreations.com: AWP enable worked but cache wouldn't stick — site sent `cache-control: no-cache` headers due to `coming-soon` plugin in maintenance mode. Deactivated the plugin (left off per Mike's direction — site now publicly visible). Also upgraded PHP 7.4 → 8.1 and fixed siteurl/homeurl from http → https.
- voicesofthewest.com: deactivated W3 Total Cache and a custom Google Fonts plugin before AWP enable.
- 5 sites (danaise.com, 4 others): LiteSpeed Cache plugin deactivated before AWP enable.
- All sites: WP-CLI run with `php -d memory_limit=512M /usr/local/bin/wp` to avoid 128MB OOM errors.

### Key Decisions

- **AccelerateWP page cache only (no object cache).** Object cache (Redis/Memcached via AWP) requires php-fpm or LiteSpeed API handler — unavailable server-wide on IX (CGI only). Page cache works with CGI. No object cache attempted.
- **Plugin conflict deactivation order.** LiteSpeed Cache, W3TC, Hummingbird, WP Defender performance, and Jetpack CDN all manage or conflict with advanced-cache.php. Deactivated before AWP enable to avoid hook conflicts. WooCommerce sites skipped e-commerce conflict check (AWP handles WooCommerce cart/checkout exclusions natively).
- **tarafulcreations.com coming-soon left deactivated.** Mike's explicit direction. Site is now publicly accessible (shows the actual site, not maintenance page).
- **rrspc.com not touched.** HTTP 000 both ports — IP 88.119.174.111 doesn't match IX server (72.194.62.5). DNS points off-server. Pre-existing condition, not caused by any changes.
- **outaboundssports.com skipped.** PHP 8.1 strict deprecation fatal in active theme — AWP cannot enable until theme is updated.
- **farwestwell.com skipped.** WordPress 5.6.14 below AccelerateWP minimum (5.8); also has stale plugins using removed PHP functions. Update required before AWP.

### Problems Encountered

- **WP-CLI OOM (128MB limit).** All WP-CLI commands on phoenixmanagedservices.com and several others hit memory exhaustion from forminator/mailchimp plugin. Fixed: prefix all WP-CLI with `php -d memory_limit=512M /usr/local/bin/wp`.
- **AccelerateWP CLI syntax error.** `cloudlinux-awp-user get --user azcomputerguru` failed. Correct syntax: `cloudlinux-awp-user --user azcomputerguru get` (flag before subcommand).
- **phoenixmanagedservices.com: AWP installed but not caching.** AWP wrote advanced-cache.php but did not add `WP_CACHE=true` to wp-config.php. WordPress only loads the drop-in if the constant is set. Fixed with sed insert before "That's all, stop editing" line.
- **fsgtucson.com HTTP 500 after AWP enable.** WP-CLI `--skip-plugins` during the blocking-agent pass left `option-tree` plugin deactivated. Theme `guru-framework` calls `ot_get_option()` from option-tree at load time — fatal without it. Fixed: reactivated option-tree.
- **tarafulcreations.com cache not sticking.** AccelerateWP respects `cache-control: no-cache` headers from WordPress — won't cache pages sending these headers. Root cause: `coming-soon` plugin sends these headers in maintenance mode. Fixed: deactivated the plugin.
- **Coord messages sent with `to_session: "PLACEHOLDER"`.** Initial heredoc used single-quoted `<<'JSON'` which blocked bash variable expansion. All three messages landed with literal "PLACEHOLDER" as the session ID. Fixed by rewriting using Python string formatting to properly expand each session ID.

### Configuration Changes

- **`.claude/settings.local.json`** — Removed `hooks` section (contained old UserPromptSubmit hardcoded path). Retained: `permissions.allow` list and `enabledMcpjsonServers`.
- **`.claude/ONBOARDING.md`** — Added "Claude Code Hooks — where each hook lives" section between GuruRMM setup and slash commands sections.
- **IX server — phoneixmanagedservices.com wp-config.php** — Added `define('WP_CACHE', true)`.
- **IX server — phoenixmanagedservices.com object-cache.php** — Renamed to `.bak` (Performance Lab conflict).
- **IX server — tarafulcreations.com wp-config.php** — siteurl/homeurl updated http → https.
- **IX server — tarafulcreations.com** — coming-soon plugin deactivated; PHP upgraded 7.4 → 8.1.
- **IX server — phoenixmanagedservices.com** — PHP upgraded 8.0 → 8.1.
- **IX server — 39 sites** — AccelerateWP page cache enabled.
- **IX server — 5+ sites** — LiteSpeed Cache, W3TC, Hummingbird, WP Defender perf module, Jetpack CDN deactivated.

### Credentials & Secrets

No new credentials.

Existing used:
- IX SSH: root@172.16.3.10 (vault: `infrastructure/ix-webhosting.sops.yaml`)
- WHM API: root credentials same vault entry, port 2087

### Infrastructure & Servers

- **IX Web Hosting** — 172.16.3.10 (SSH/WHM), external IP 72.194.62.5 (Apache/LiteSpeed)
- **AccelerateWP** — CloudLinux page cache; CLI: `cloudlinux-awp-user --user <cpanel_user> enable --feature=accelerate_wp`; config per-site at `/home/<user>/cloudlinux-awp-user-configuration.json`
- **rrspc.com** — DNS off-server (IP 88.119.174.111, not IX). Pre-existing. Not touched.
- **tarafulcreations.com** — coming-soon deactivated; site now publicly live. PHP 8.1. AWP page cache active.
- **phoenixmanagedservices.com** — WP_CACHE added, AWP active, PHP 8.1. azcomputerguru cPanel account.
- **fsgtucson.com** — option-tree reactivated, AWP active.
- **outaboundssports.com** — AWP skipped; PHP fatal in theme.
- **farwestwell.com** — AWP skipped; WP 5.6.14 below minimum.

### Commands & Outputs

```bash
# AccelerateWP enable (correct syntax — flag before subcommand)
cloudlinux-awp-user --user <cpanel_user> enable --feature=accelerate_wp

# WP-CLI with memory override (required on this server)
php -d memory_limit=512M /usr/local/bin/wp plugin deactivate litespeed-cache --path=/home/<user>/public_html --allow-root

# WP_CACHE insert (phoenixmanagedservices.com)
sed -i "s/\/\* That's all, stop editing/define( 'WP_CACHE', true ); \/\/ Added by AccelerateWP\n\/\* That's all, stop editing/" /home/azcomputerguru/public_html/phoenixmanagedservices.com/wp-config.php

# HTTP timing test (after caching)
curl -s -o /dev/null -w "%{time_total}" https://danaise.com/          # → 0.390s
curl -s -o /dev/null -w "%{time_total}" https://phoenixmanagedservices.com/  # → 0.69s

# Verify AWP caching (X-Cache header check)
curl -sI https://danaise.com/ | grep -i "x-cache"   # → X-Cache: HIT

# fsgtucson.com option-tree reactivation
php -d memory_limit=512M /usr/local/bin/wp plugin activate option-tree \
  --path=/home/fsgtucson/public_html --allow-root --skip-plugins --skip-themes
```

### Pending / Incomplete Tasks

- **[SECURITY — IX]** packetdial.com webshell: `/home/packetdial/public_html/x919.php` — HTTP 200 from external IP, needs deletion and investigation
- **[WP update needed]** outaboundssports.com — PHP 8.1 deprecation fatal in active theme; AWP blocked until theme updated
- **[WP update needed]** farwestwell.com — WP 5.6.14 below AccelerateWP minimum (5.8); stale plugins with removed PHP functions
- **[Manual — BEAST]** `nssm restart ClaudeToolsDiscordBot` — required for Rob Williams access to take effect
- **[Manual — Physical/ScreenConnect]** PST-SURFACE: reinstall GuruRMM agent 0.6.27, verify IKEv2 VPN + cert
- **[Machine cleanup — pending]** Mac, BEAST, Howard: remove UserPromptSubmit hooks from `~/.claude/settings.json` and `.claude/settings.local.json` per coord messages sent this session

### Reference Information

- AccelerateWP CLI reference: `cloudlinux-awp-user --user <u> get|enable|disable --feature=accelerate_wp`
- WP-CLI memory workaround: `php -d memory_limit=512M /usr/local/bin/wp`
- IX server Python paramiko scripts: `D:/claudetools/.claude/tmp/ix_ssh.py`, `ix_all_sites.py`
- tarafulcreations.com: live (coming-soon off), PHP 8.1, AWP active, https siteurl fixed
- phoenixmanagedservices.com: subsite of azcomputerguru cPanel account; AWP active, WP_CACHE fixed
- Sites skipped (blockers): outaboundssports.com (theme fatal), farwestwell.com (WP too old)
- Sites skipped (abandoned): 11 accounts with stale/parked installs — no AWP needed
