Commit Graph

1651 Commits

Author SHA1 Message Date
f987812fe5 unifi-wifi: model-rank + optimize-radios run on cloud-connector data (non-UOS consoles)
Both analyses now accept `--console "<name>"` and run against the UniFi cloud connector
instead of the UOS Mongo server, so RF airtime tuning works on standalone/non-UOS consoles
(e.g. Brooklyn/Skybar). The UOS Mongo path is unchanged.

- New shared analyzer scripts/rf-analyze.py: pulls per-AP/band airtime history via the
  connector POST /stat/report/hourly.ap (SAME schema as ace_stat.stat_hourly) + /stat/device
  for names/zones, derives cu_interf = cu_total - cu_self_rx - cu_self_tx, and runs the SAME
  model-rank ranking and optimize-radios greedy power-down/disable logic (ported faithfully).
- Roam graph (/stat/event) is usually empty on small/stationary sites -> graceful degrade:
  model-rank ranks by airtime pressure; optimize-radios returns power-down candidates + 0
  disables (coverage-safe). NEIGHBOR_JSON (SNR matrix) still enables disables, as on UOS.
- model-rank.sh / optimize-radios.sh: added the `--console` route (resolves the key from
  vault services/unifi-site-manager, execs rf-analyze.py). Validated on Brooklyn/Skybar:
  2.4GHz saturated (Yoga AP cu 63%/interf 55%), 5GHz idle (1-5%) - the expected pain-band split.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 08:43:09 -07:00
6fdc21d955 unifi-wifi: cloud Site Manager backend (gw-sitemanager.sh) + UOS-parity connector tier
New backend reaching ANY of the ~36 ACG UniFi consoles remotely via api.ui.com with the
account key (vault services/unifi-site-manager) - no UOS server, no LAN/VPN. Mapped the API
surface empirically (key live), corroborated by grok+gemini web search:

- Tier 1 (Site Manager): fleet/devices/sites/isp commands - inventory, site health (counts,
  IPS, ISP/ASN), and WAN/ISP time-series (latency/throughput/downtime).
- Tier 2 (CLOUD CONNECTOR -> console LOCAL Network API = UOS PARITY): the `net` command proxies
  /v1/connector/consoles/<id>/proxy/network/api/s/<site>/stat/{device,sta}, returning the SAME
  ace_stat depth as the UOS Mongo path - per-radio cu_total airtime/channel/bw/tx_power/num_sta/
  satisfaction and per-client rssi/signal/noise/satisfaction/rates. Verified live on Brooklyn/
  Skybar (standalone UDM, WAN-firewalled): `net brooklyn radios` + `net brooklyn clients` work.

This achieves parity with (and broader coverage than) the UOS server for non-UOS consoles.
Added references/site-manager-api.md (full catalog + 3 tiers), a Plane 3 note in SKILL.md, and
updated the reference memory. Read-only; POST actions (device restart, client block) exist, not wired.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 08:32:00 -07:00
29b33c686a acg-website: Phase 3B - radio show promotion, funnel, enhanced CTAs, layout density
Radio Show Promotion:
- Add LIVE badge to header phone with subtle pulse animation
- Add radio promo bar under hero (show name, time, call-in number)
- Radio ticker at bottom remains from Phase 3A

3-Step Visual Funnel:
- New funnel-steps section after Trust
- Progression: 1. Build estimate → 2. Talk it through → 3. Month-to-month start
- Interactive number badges with hover lift + color fill
- Mobile responsive (stacks vertically on small screens)

Strengthen Calculator CTAs:
- Pricing teaser: Make 'Build your exact price' primary button (was more-link)
- All 6 service cards: Add inline 'See what this costs →' calculator links
- Guides prospect directly to calculator from any service mention

Increase Vertical Rhythm:
- Section padding: clamp(2.75rem, 5.5vw, 4.25rem) for breathing room
- Service list: +1.5x base margin-bottom after dense grid
- Dispatch grid: +1.5x base margin-bottom after blog cards

All changes deployed to ww9.azcomputerguru.com and verified live.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-17 07:15:41 -07:00
4b631f681c acg-website: Phase 3A enhancements - premium polish + dark mode fix
- Add timing system: --t-fast/med/slow + cubic-bezier easing vars
- Enhanced button/card hover: subtle lift + box-shadow + filter
- Nav link underline wipe effect with accent color
- Form input focus: accent border + 25% opacity outline
- Micro-interactions: stepper scale, switch snap, FAQ rotation
- Reveal animations: opacity + translateY with 55ms stagger
- Radio promo bar CSS + pauseable ticker on hover
- Dispatch board: 1px grid + left accent rule + tighter cards
- CRITICAL FIX: orphaned CSS selector causing dark mode white boxes

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-17 07:04:11 -07:00
311a45abee acg-website-showcase: curate brand kit to forward-relevant assets
Per Mike: don't keep the full archive tracked. Trimmed the brand kit from 34M -> 14M,
keeping only forward-relevant assets: the StyleGuide PDF, current logos
(transwhite/flatwhite) + vector master (guru-vector.eps, moved out of Old/), Guru
Icons, the Lato family (+ OFL + README), Colors reference, social avatar, and the
2025 letterhead (png + docx). Removed legacy Old/ marks, business cards, raster
flat-icon sheets, the superseded 2021 letterhead, and generic stock images.
(Original archive remains recoverable from git history.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 06:19:01 -07:00
8e2d097761 sync: auto-sync from Mikes-MacBook-Air.local at 2026-06-17 06:18:23
Author: Mike Swanson
Machine: Mikes-MacBook-Air.local
Timestamp: 2026-06-17 06:18:23
2026-06-17 06:18:26 -07:00
41a30178e7 acg-website-showcase: add ACG master brand kit
Imported the canonical "Branding Stuff" archive (2026-06-15) into the website
project at projects/acg-website-showcase/brand-kit/: logos (transwhite/flatwhite/
vector EPS), full Lato font family (+ SIL OFL license), Guru Icons (16-512px),
brand Colors reference, social avatar, letterhead (2021/2025), business cards,
flat icon sheets, and stock images. 64 files. Added a README documenting contents
+ licensing (Lato = OFL; verify stock-image licenses before public reuse).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 06:15:01 -07:00
f6081a027b sync: auto-sync from HOWARD-HOME at 2026-06-17 00:09:45
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-17 00:09:45
2026-06-17 00:09:53 -07:00
063bc54bce sync: auto-sync from HOWARD-HOME at 2026-06-16 23:54:06
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-16 23:54:06
2026-06-16 23:54:14 -07:00
1c6b88a285 sync: auto-sync from HOWARD-HOME at 2026-06-16 23:33:45
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-16 23:33:45
2026-06-16 23:33:54 -07:00
5ad25d1b4c sync: auto-sync from HOWARD-HOME at 2026-06-16 21:34:19
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-16 21:34:19
2026-06-16 21:34:40 -07:00
16a8dfffd1 unifi-wifi: fix apply-wlan wlan_bands 6e->6g; add 5GHz + 6GHz phases to Cascades runbook
- apply-wlan.sh: wlan_bands token was "6e" but this controller stores "6g" (verified live on Cascades
  Guest SSID) -> setting 6 GHz membership would have failed. Fixed band values + option names (5g6g/6g/all).
- Cascades 2.4 runbook: folded in Phase 5 (5 GHz: width 80->40 on 76 radios; channel plan with the
  DFS decision flagged -- DFS empirically clean here, so including clean-DFS gives ~20 channels vs ~5
  non-DFS-only for 77 APs) and Phase 6 (6 GHz: root cause = production SSID CSCNet not on 6 GHz [bands
  2g,5g only]; add 6g + enable bss-transition; band-steering already on). Per Howard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 21:34:40 -07:00
e6a0efa57c cascades 2.4 runbook: Floor 1 per-AP (skip 128/108) instead of zone — no pointless 128 re-enable 2026-06-16 21:34:39 -07:00
bcebae439a cascades 2.4 runbook: exclude Floors 5 & 6 per Howard; Floor 4 power-down done 2026-06-16 21:34:39 -07:00
7f80febecd acg-website: update skin switcher labels (remove Paper references)
Updated aria-label and title attributes on skin toggle button to reflect
current 3-skin configuration: Bold / Midnight / Verdigris

Deployed to ww9.azcomputerguru.com

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-16 20:34:41 -07:00
45f6676468 acg-website: remove ledger background ruling pattern
Removed repeating-linear-gradient background-image that creates horizontal
ledger lines. Bold design has no ledger rulings - clean backgrounds only.

Deployed to ww9.azcomputerguru.com

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-16 20:33:43 -07:00
7515af3309 acg-website: remove Paper/Ledger skin, set Bold as default
- CSS: Bold tokens now at :root (bone/near-black palette, signal orange)
- JS: skin switcher cycles Bold/Midnight/Verdigris (default: bold)
- HTML: all 7 pages default to bold skin
- Docs: README + DESIGN.md rewritten for Bold design language
- Deployment: live at ww9.azcomputerguru.com (IX hosting, grey-cloud DNS)

Paper/Sonoran Ledger skin dropped per user direction. Single-page ledger
version in root retained as archived reference pattern.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-16 20:30:10 -07:00
a073f66b92 skills(brainstorming): make request-only, not auto-trigger
Upstream description ("You MUST use this before any creative work...") would
auto-fire the brainstorming skill on routine feature/code work. Rewrote the
frontmatter description to invoke ONLY when the user explicitly asks to
brainstorm/design. Methodology body (incl. HARD-GATE) unchanged. Noted in SOURCE.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 20:22:59 -07:00
6122efe98c skills: harvest 4 MIT dev skills from obra/superpowers (awesome-claude-skills)
From the ComposioHQ/awesome-claude-skills list. Checked licenses BEFORE copying:
- threat-hunting-with-sigma-rules: repo is gone (GitHub 404) -- not harvested.
- forensics (mhattingpete): repo restructured, those skills no longer exist -- not harvested.
- pdf / mcp-builder (Anthropic official): LICENSE.txt FORBIDS copying out of the
  Service / derivatives / redistribution -- NOT harvestable into this repo (install via
  the official Claude Code marketplace instead if wanted).
- obra/superpowers: MIT -> the only legally harvestable set; imported with attribution.

Imported (each with its own MIT LICENSE copy + SOURCE.md provenance, commit a21956e48c13,
ASCII-normalized to house style, no emojis):
- using-git-worktrees
- test-driven-development (+ testing-anti-patterns.md)
- root-cause-tracing (+ find-polluter.sh helper, emojis -> ASCII markers)
- brainstorming (methodology only; upstream visual websocket server intentionally omitted)

Faithful imports -- content not reworded beyond ASCII typography/emoji normalization.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 20:22:59 -07:00
7590155499 ollama: fix broken endpoint auto-detect in OLLAMA.md one-liner (RTFM audit)
Audited the Ollama reference (no wrapper script — it's the OLLAMA.md doc + inline
HTTP-API call pattern) against the live server (Ollama 0.30.8 on GURU-5070):
- /api/chat + think:false + res['message']['content'] confirmed working (clean
  output, no thinking leak) -- the core call pattern is correct.
- All referenced models exist on the server (qwen3:8b, qwen3.6:latest, qwen3:14b,
  codestral:22b, nomic-embed-text).

Real bug found + fixed: the "Preferred one-liner" auto-detected the endpoint with
`urlopen(...)` used as a truthiness test. urlopen RAISES URLError on a down host
(proven), so the ternary's fallback branch was dead code -- it crashed on a down
localhost instead of failing over to Beast, and it did a per-call probe that
contradicts the doc's own "read endpoint from identity.json, no probe" rule 30 lines
above. Replaced with the identity.json endpoint+model pattern (also swaps the
hardcoded qwen3:14b for the per-machine prose_model). Validated verbatim end-to-end.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 20:22:59 -07:00
69638887ab wiki: compile cascades-tucson (full) — WiFi RF + network/pfSense + SSH backend, 55.75h 2026-06-16 20:08:02 -07:00
1b8ab26e87 sync: auto-sync from HOWARD-HOME at 2026-06-16 19:40:32
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-16 19:40:32
2026-06-16 19:40:40 -07:00
18a4884ee9 errorlog: wiki-compile --full subagent friction (32k output crash on large article) 2026-06-16 19:30:49 -07:00
bc0ceea26c wiki: compile cascades-tucson (full) - voice VLAN plan, CSCNet PPSK correction, CS-SERVER RAID/backup 2026-06-16 19:29:50 -07:00
2b123679f9 sync: auto-sync from HOWARD-HOME at 2026-06-16 19:29:08
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-16 19:29:08
2026-06-16 19:29:21 -07:00
e09ff5dc9b agy(gemini): RTFM audit — confirmed healthy, version + verified-date refresh
Audited the Gemini wrapper against the CLI's bundled help/README (gemini 0.45.2),
same pass as the grok skill. Unlike grok, found NO functional bug:
- All flags correct and real: -p, --skip-trust, -o json, --approval-mode plan|yolo,
  --include-directories, -m (verified against `gemini --help`).
- JSON schema {session_id, response, stats} -> .response confirmed via live probe.
- Pinned model gemini-3.1-pro-preview STILL VALID (live PONG); the GA-looking
  gemini-3.1-pro and gemini-3-pro both ModelNotFoundError -> keep the -preview suffix.
- Default text model is gemini-3.1-flash-lite (by design; verify/review/search/image
  pin pro). No thought-suppression flag exists in the CLI, so the gresponse() reasoning
  -leak scrub stays (justified, signature-gated, byte-exact otherwise).
- Live `search` re-validated end-to-end through the wrapper (58s, grounded sources).

Only change: version 0.45.1 -> 0.45.2 in SKILL.md + wrapper header, and refreshed the
verified-date notes with the 2026-06-17 re-validation findings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 19:25:07 -07:00
a242797908 grok: fix xsearch (multi-agent web_search), pin grok-build, RTFM doc sweep
Root-caused the long-standing `ask-grok.sh xsearch` "no result (stopReason=)"
failure by reading Grok's bundled docs (~/.grok/docs/user-guide + README) instead
of probing:
- web_search runs a SEPARATE multi-agent model (grok-4.20-multi-agent), so the
  wrapper's blanket --no-subagents strangled it -> indefinite hang, 0 bytes. Scoped
  --no-subagents OFF xsearch; use --yolo (documented headless tool-run posture).
- xsearch prompt mandated X/Twitter search on every call (slow multi-agent) and the
  budget was 240s -> still timed out. Now web-primary (X only when relevant), 300s.
  Validated end-to-end through the wrapper: 23s, correct answer + 3 sources.

Model: pin -m grok-build (xAI flagship, 512k, the documented default) for the
reasoning modes (text/verify/review*) so quality is deterministic and not at the
mercy of the runtime default (this machine drifted to grok-composer-2.5-fast, a fast
Cursor coding model). xsearch + image/video keep the runtime default. Validated text
mode on grok-build (13s).

Doc accuracy (SKILL.md): corrected the model facts (default, the separate web_search
model, --effort unsupported on grok-build per supports_reasoning_effort:false);
documented the xsearch subagent exception. Fixed a stale in-script comment claiming
--rules/--disallowed-tools "tripped the CLI" (both are valid headless flags).

memory: add feedback_interview_ai_read_docs (read bundled docs / interview the model
before probing) + index; errorlog correction.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 19:25:07 -07:00
58ecc5ad40 unifi-wifi: pfSense gateway access via SSH (pfSense-ssh.sh) + pfSense health section; layer OFF HOLD
DECISION (Mike, 2026-06-16): drop the RESTAPI package — VPN + SSH shell reads the same data and makes
changes. Confirmed Cascades pfSense is Plus 25.07-RELEASE (current; the "too old" premise was wrong) and
admin SSH = real shell (no menu). The upgrade/package blocker is moot; compat layer is off hold.

- NEW scripts/pfsense-ssh.sh: audit (version/WAN-media/gateway-events/DHCP-exhaustion/states/DNS/load/NIC),
  dhcp (pool utilization + no-free-leases), run "<cmd>" (arbitrary, incl changes; operator-gated). Cred
  from clients/<slug>/pfsense-firewall; system OpenSSH via askpass. Validated live on Cascades.
- audit report: added "pfSense health check (2026-06-16)" — DHCP NOT exhausted (192.168.0.0/22 pool 270/507,
  0 no-free-leases), DNS up, dual-WAN stable (no gateway flaps), states/load healthy => gateway is NOT a
  WiFi factor; the 2.4 GHz RF work is the sole fix. (Minor: igc3/WAN2 I225 2.5G counter quirk, not a fault.)
- ROADMAP §E + SKILL.md updated to the SSH backend decision; REST pfsense-backend.sh kept dormant/optional.
- Remaining: named gated CONTROL verbs over SSH (easyrule block-ips, pf/fw toggles) + optional gw-* dispatch.
- Closed obsolete coord todo (upgrade-pfSense-for-RESTAPI).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 18:42:54 -07:00
e42ad8f163 sync: auto-sync from HOWARD-HOME at 2026-06-16 18:23:40
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-16 18:23:40
2026-06-16 18:23:49 -07:00
32dd949d7f sync: auto-sync from GURU-5070 at 2026-06-16 18:13:39
Author: Mike Swanson
Machine: GURU-5070
Timestamp: 2026-06-16 18:13:39
2026-06-16 18:13:57 -07:00
718bce3525 sync: auto-sync from HOWARD-HOME at 2026-06-16 18:10:13
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-16 18:10:13
2026-06-16 18:10:43 -07:00
54c7f9940d harness: PS2 guard for onboarding probe + Windows quote-stripping memory
onboarding-diagnostic.ps1: add a PowerShell-version guard. The probe is PS3+ by
design (Get-CimInstance, [ordered], ConvertTo-Json); on stock PS2 (Win7 SP1 /
2008 R2 without WMF) it crashed with cryptic [ordered] errors and emitted empty
DIAG-JSON (first hit: AMT-PC). Now on PS<3 it emits a legible, parseable result
inside the DIAG-JSON markers (hand-built JSON) with a WMF 5.1 / KB3191566
remediation hint instead. Parses clean. True PS2-native probe stays an RMM Thought.

memory: add feedback_windows_quote_stripping (+ index) consolidating the two
recent embedded-double-quote incidents (PowerShell->curl.exe CommandLineToArgvW,
RMM->cmd.exe shutdown /c) into one root cause + fix, so future ref= entries land.

errorlog: the two self-logged entries from #32333 (preview-skip friction,
AMT-PC/Scileppi conflation correction).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 18:10:11 -07:00
08fcafa0a4 sync: auto-sync from HOWARD-HOME at 2026-06-16 18:09:18
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-16 18:09:18
2026-06-16 18:09:27 -07:00
d6cbfb3e50 sync: auto-sync from HOWARD-HOME at 2026-06-16 17:03:02
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-16 17:03:02
2026-06-16 17:03:10 -07:00
8c048c3d51 cascades: 2.4 GHz remediation runbook for tonight (mesh-safe power-down + per-floor disable, gated)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 16:46:17 -07:00
3374483cd6 unifi-wifi: coverage-thin mesh-awareness — never disable wireless-mesh APs or their parents
Howard caught a real hazard: coverage-thin was mesh-blind. At Cascades, 2nd Floor Atrium is the
wireless-mesh PARENT for CC Bridge + salon (backhaul ch36/5GHz), and 206 U7 Pro carries 108. The tool
had listed 2nd Floor Atrium / CC Bridge / 206 as 2.4 disable targets. Although the backhaul is 5GHz
(so a 2.4-radio disable wouldn't drop it), touching infra APs that feed others is needless risk.

Fix: fetch live uplink topology (stat/device); build the mesh set = wireless-uplink APs UNION their
parents; exclude them from disable (kept as coverers if their 2.4 is on); print MESH-PROTECTED line.
Falls back with a clear WARNING if no controller cred. Cascades now auto-excludes 108/206/2nd Atrium/
CC Bridge/salon; resilient plan 34->33. Also verified SSIDs are not AP-pinned (broadcasting_aps off),
so no client is orphaned by a radio disable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 16:43:08 -07:00
6f77222bcb unifi-wifi: coverage-thin apply hint -> per --ap (was --zone, which would disable a whole floor)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 16:28:35 -07:00
f936224de8 unifi-wifi: add coverage-thin.sh — 2.4 coverage-redundancy disable planner (active-2.4 aware)
Answers "which 2.4 radios can we turn OFF given over-coverage, based on AP proximity." Greedy
dominating-set on the AP-to-AP 2.4 SNR layer: disables radios whose area stays covered by a nearby
ACTIVE-2.4 neighbor, maximizing interference-airtime removed without opening a 2.4 hole. Caps per-zone,
guards coverer capacity, flags single-coverer (low-resilience) disables, reports co-channel before/after.

Why separate from optimize-radios: optimize uses band-AGNOSTIC physical adjacency, so it counts an AP
whose ng radio is DISABLED as a "coverer" via its 5/6 GHz (observed: it proposed disabling 127/229/330/428
"covered by 128" — but 128's 2.4 is already disabled => those would be 2.4 holes). coverage-thin uses the
2.4 SNR layer specifically and only counts neighbors whose 2.4 stays ON.

Cascades (live): aggressive MINCOV=1 -> disable 36/76; resilient MINCOV=2 -> disable 34/76 with >=2 active
2.4 coverers each; co-channel ch6 28->13, ch11 25->13, ch1 20->13; ~2400 interference-airtime pts removed.
Read-only; needs NEIGHBOR_JSON. SKILL.md step 3b.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 16:17:54 -07:00
80384a79f4 unifi-wifi: radio-usage.sh --ap mode — per-device 2.4 history + steerable-vs-legacy tagging
Adds `radio-usage.sh <site> <band> --ap "<AP name>"`: lists the devices on one AP's band by merging
live clients (stat/sta) with recent association events (wifi_connectivity_event, band-aware), enriched
from ace.user identity. Tags each device steerable vs legacy:
  - from events: DUAL (also seen on 5/6 GHz -> steerable) vs NG-ONLY (2.4-only -> legacy/IoT)
  - fallback when no event in the (short ~1d) retention window: randomized MAC = modern phone/laptop
    (likely 5G/steerable) vs fixed vendor OUI = likely IoT/legacy.
Decision value: steerable -> fix via band-steering/min-RSSI; a legacy/IoT device present argues AGAINST
disabling that 2.4 radio. Needs controller cred for the live BSSID (vap_table) map; honest about the
short event retention. Validated live on Cascades (347, Dining Room).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 15:51:13 -07:00
659c3a2bda unifi-wifi: add radio-usage.sh — per-AP band client-usage history (disable-safe vs power-down)
Answers "is this 2.4 radio actually used?" from accumulated controller stats (ace_stat.stat_daily,
~77d). Reports per-AP time-avg concurrent users (<radio>-num_sta_avg) + peak station snapshot
(<band>-num_sta), distinguishing avg~0/peak>0 (takes bursts -> POWER-DOWN) from peak==0 (genuinely
unused -> disable-safe). With NEIGHBOR_JSON it crosses low-use APs against the AP-to-AP SNR matrix to
emit a defensible safe-to-disable shortlist (low-use AP + strong overlapping neighbor with headroom),
noting mutual-coverage conflicts and deferring conflict-free selection to optimize-radios.

Validated live on Cascades: of 76 APs only 1 has peak==0 over 77d (the offline AP 108); every other
2.4 radio takes real client bursts (peaks 5-58) at very low avg (12 APs <0.5 concurrent). I.e. the
usage history independently CONFIRMS the conservative power-down-not-disable call. Read-only (Mongo
plane). Uses var-assignment to avoid the legacy-mongo REPL echo. SKILL.md documents it as step 2b.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 15:38:26 -07:00
e1031ae91a unifi-wifi: skill health pass — fix optimize-radios stray REPL echo + ASCII-clean all output
Full verification of the skill against Cascades (live):
- All 19 scripts syntax-clean.
- Controller-side read-only validated live: sites, audit-site, switch-audit, live-stats, model-rank,
  optimize-radios, monitor-run, gw-audit. Dry-run apply paths validated: apply-radio, apply-wlan,
  client-control, device-control. AP-side mechanism validated: SSH auth + /proc/ui_neighbor read on a
  sample AP; full neighbor-collect (74-AP SNR sweep) -> channel-plan end-to-end produced a 1/6/11 plan.

Fixes:
- optimize-radios.sh: the `for(k in prof)` loop's numeric completion value was REPL-echoed by the legacy
  mongo shell (stray "94.56..." line in output). Terminated the loop body with `void 0` to suppress it.
- ASCII-clean printed output (CLAUDE.md no-non-ASCII): replaced em-dashes / Unicode arrows / § that
  reached stdout and rendered as `?`/mojibake on the Windows console, across optimize-radios,
  neighbor-collect, survey-collect, dfs-check, audit-site, sites, monitor-run, apply-radio, apply-wlan,
  pfsense-backend. (Comment-only non-ASCII left as-is; never printed.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 15:08:35 -07:00
7e2f49020a sync: auto-sync from HOWARD-HOME at 2026-06-16 14:11:33
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-16 14:11:33
2026-06-16 14:11:42 -07:00
e3bb7d3f95 unifi-wifi: pfSense compat layer ON HOLD — Cascades pfSense too old for RESTAPI pkg, needs upgrade first
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 14:11:33 -07:00
1118594cd2 unifi-wifi: pfSense gateway compat layer (§E) — REST backend + dispatch inside gw-audit/gw-control
Per Howard's decision (2026-06-16, "try what Mike wanted"): Mike's §E open decisions resolved as
REST API package backend + dispatch INSIDE the existing gateway verbs (his lean), not sibling scripts.

- NEW scripts/pfsense-backend.sh: pfSense REST API (pfSense-pkg-RESTAPI v2, X-API-Key) driver exposing
  the same verbs as gw-control (audit, pf-list/disable/enable/delete/set-ports, fw-list/disable/enable,
  block-ips) + a `setup` helper. Writes --apply-gated with per-object rollback to .claude/tmp + firewall/apply.
- gw-audit.sh: when num_gw=0 and a clients/<slug>/pfsense-api cred is vaulted (or --pfsense <slug>),
  appends the pfSense WAN/DHCP/firewall audit; else prints the setup hint. (captures num_gw to gate.)
- gw-control.sh: same-verb auto-dispatch to pfsense-backend when a pfSense cred resolves for the site.
- SKILL.md [PROPOSED]->[SCAFFOLDED]; ROADMAP §E open decisions marked resolved.

STATUS: scaffolded. BLOCKED/setup/no-cred paths tested; gw-audit dispatch validated live (Cascades
num_gw=0 -> hint). Live REST calls pending a reachable pfSense with the API pkg + a vaulted key; v2
endpoint paths must be verified against the installed API version on first live run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 13:51:10 -07:00
708379732e sync: auto-sync from HOWARD-HOME at 2026-06-16 13:43:14
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-16 13:43:14
2026-06-16 13:43:23 -07:00
0956f76cb2 sync: auto-sync from HOWARD-HOME at 2026-06-16 13:30:26
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-16 13:30:26
2026-06-16 13:30:35 -07:00
2f6057518d sync: auto-sync from HOWARD-HOME at 2026-06-16 13:12:16
Author: Howard Enos
Machine: HOWARD-HOME
Timestamp: 2026-06-16 13:12:16
2026-06-16 13:12:26 -07:00
34091500ee sync: auto-sync from GURU-5070 at 2026-06-16 09:02:24
Author: Mike Swanson
Machine: GURU-5070
Timestamp: 2026-06-16 09:02:24
2026-06-16 09:02:39 -07:00
a32dfc33fa syncro: invoice-note policy — block hours remaining, low-block (<4hr) renew + Winter tag, recurring sweep
Extends the invoice Message (note) automation into a single reusable helper
set_invoice_note <invoice_id> <customer_id> [pre_billing_prepay]:
  - no block (prepay_hours==0)  -> "Interested in discounted labor? Ask us about block-rate pricing."
  - block, >=4 hrs left         -> "Block hours remaining: N."
  - block, <4 hrs left          -> remaining + renew line, AND tags Winter (<@624666486362996755>)
                                   in #bot-alerts (low-block heads-up; mentions ping, no allowed_mentions)
Pre-billing prepay arg keeps a just-depleted block counted as a block customer (shows renew, not upsell).
Never clobbers a non-empty note.

Wired into billing Step 3 (set_invoice_note "$INVOICE_ID" "$CUST_ID" "$PREPAY"), and a new
"Recurring invoice note sweep" applies the same policy to Syncro's auto-generated recurring invoices
(schedule_id != null, recent, current balance) — idempotent, run after each recurring run.

Branch logic + a real e2e note set/restore validated on the ACG internal test account (#67741); the
<4hr Winter alert was stubbed in testing so no real ping fired.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 08:56:42 -07:00
864f4d0a33 syncro: document Invoice Message (note field) + auto block-rate hint for non-block customers
The on-screen "Invoice Message" text block IS the invoice `note` field, editable via
PUT /invoices/{id} {"note": "..."} (response {"invoice": {...}}). Verified on the ACG
internal test account (#67741: set/verify/restore).

Billing flow now sets a one-line upsell hint on the invoice note — "Interested in
discounted labor? Ask us about block-rate pricing." — ONLY for customers with no prepaid
block (prepay_hours == 0). Block customers (prepay_hours > 0) get no hint; never clobber
a non-empty note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 08:48:25 -07:00