Initial commit: AVWatch v1.0.0 with .gitignore and CLAUDE.md

This commit is contained in:
2026-09-24 13:07:21 -04:00
commit ea70a9cb5f
38 changed files with 9604 additions and 0 deletions
+435
View File
@@ -0,0 +1,435 @@
# AVWatch
Update and risk monitoring for a live production AV fleet.
It answers one question, per device, every week: **a new version exists — is it
safe for us to install, or should we hold off?**
It does that by finding the current release, searching Reddit, GitHub and the
wider web for people reporting that the release broke something, and then
producing a **Go / Wait / Avoid** call with the evidence attached. It is built
around the assumption that in a church production environment, running a
release behind costs almost nothing and a dead device on Sunday morning costs
a great deal — so the burden of proof is on the update, not on waiting.
---
## What you get
- **A local HTML dashboard** (`reports/latest.html`) — every item, grouped by
what needs a decision, with the community evidence one click away.
- **An automated Monday email briefing** to whoever you list, with the full
dashboard attached.
- **Mid-week automated scans** that keep the dashboard current and notice new
releases as they land.
- **Three layers of verdict**, all shown side by side, because you asked for
all three:
1. **Claude's reasoning verdict** — reads the release notes and the community
posts, filters the irrelevant ones, and explains its call.
2. **A rule-based score** — release age against your soak policy, size of the
version jump, keyword severity of the reports, criticality weighting. Runs
always, needs no API key.
3. **The raw cited evidence** — every post it looked at, linked, so you can
overrule both engines.
When the two engines disagree, the report says so explicitly. That
disagreement is the signal to go read the evidence yourself.
---
## Not sure what to do next?
```bash
python -m avwatch worksheet
```
Prints a walk-the-rack checklist: what to look at, where the version is
displayed on that specific box, and the exact command to type. Coupled gear
comes first, because a matched set cannot be checked until both halves are
known.
You do not have to finish it. Every line helps, and nothing breaks while lines
are missing.
---
## Quick start
```bash
cd "C:\Users\Live Stream\Desktop\Claude\avwatch"
python -m pip install -r requirements.txt
```
```bash
copy config.example.toml config.toml
```
Edit `config.toml` — at minimum the `[email]` block. Then:
```bash
python -m avwatch doctor
```
That tells you exactly what is and is not configured. Then a first real run:
```bash
python -m avwatch scan --no-llm
```
Open `reports\latest.html`.
---
## Version coupling — the thing that actually breaks services
In a live AV fleet the update that ruins a Sunday is rarely a bad release. It
is a **mismatch**: the ATEM got flashed but not the 2 M/E panel, the AD4Q
receivers but not the AD1 packs, the VX1000 but not the receiving cards. Judging
each item on its own merits cannot see any of that.
So items can declare dependencies on each other:
```yaml
- id: atem-constellation-4k
update_group: atem
coupled_with:
- {id: atem-2me-advanced-panel, relation: must_match,
note: "the panel goes offline if the switcher moves without it"}
```
| Relation | Meaning |
|---|---|
| `must_match` | Versions must be *equal* or they will not talk. Shure TX/RX, Teradek TX/RX, SoundGrid, ATEM + panel. |
| `must_be_at_least` | This item must be at or above the other. Config tools over the devices they configure (Wireless Workbench, RedNet Control). |
| `carries_firmware_for` | This is the utility that flashes the other. Update the tool first, then re-check the device. |
| `host_of` | Platform under dependents. macOS over Pro Tools, Pro Tools over its plugins. |
| `content_for` | Show files, libraries, calibration data. Usually forward-only — back up first. |
The rules AVWatch then enforces:
- **A coupled item is never reported as plain "go".** It becomes "go, together
with X and Y", with the partners named.
- **A live mismatch leads the report** in its own *Version mismatch — broken
now* section, because that is a present fault, not a future risk.
- **Edges are mirrored.** Only one half of a pair needs to declare the
relationship; both halves get warned.
- **`update_group`** marks items that must be planned and frozen as one set.
91 dependency edges across 8 groups ship configured: ATEM trio, Companion pair,
DiGiCo console + rack, WING + Edit + DP48, Waves SoundGrid, Shure Axient and
QLX-D sets, Vista + M1, both operating systems over their dependent stacks.
Check the graph any time with `avwatch doctor`.
---
## The one thing you must do
`installed:` ships blank on every item, because only you know what is actually
running in your racks. Until you fill those in, AVWatch can tell you a newer
version exists but not whether you are behind — **and coupling can be described
but never checked**, since comparing two versions needs both of them.
Record them as you go:
```bash
python -m avwatch set-installed atem-constellation-4k 10.4
```
That edits one line and leaves the file's comments intact.
**Start with the coupled clusters, not alphabetically.** `avwatch doctor` lists
them. Getting the ATEM trio, the Shure RF sets and the DiGiCo pair recorded
unlocks the mismatch detection that is the most valuable thing here; the long
tail of plugins can wait.
---
## Credentials
All optional, all read from environment variables so nothing sensitive lives in
a config file. Set them with `setx` so scheduled tasks inherit them, then open
a new shell:
```bash
setx ANTHROPIC_API_KEY "sk-ant-..."
```
| Variable | What it buys you |
|---|---|
| `ANTHROPIC_API_KEY` | The reasoning verdicts, **and** version lookups for the ~60 vendors that cannot be scraped. Without it you get rule-based scores and a much shorter list of tracked versions. |
| `AVWATCH_SMTP_PASSWORD` | The email digest. |
| `AVWATCH_GITHUB_TOKEN` | Lifts GitHub from 60 to 5,000 requests/hour. A classic token with **no scopes ticked** is enough. Worth setting. |
| `AVWATCH_REDDIT_CLIENT_ID` + `AVWATCH_REDDIT_CLIENT_SECRET` | Proper Reddit search. Strongly recommended — see below. |
### Reddit is worth the five minutes
Reddit **blocks unauthenticated API access** (verified: plain `.json` endpoints
return HTTP 403). Without credentials AVWatch falls back to scraping
DuckDuckGo for `site:reddit.com` results, which works but is rate-limited and
noisier.
r/livesound, r/VIDEOENGINEERING and r/churchtech are the highest-signal
sources for this exact fleet, so this is the single best upgrade available:
1. Go to <https://www.reddit.com/prefs/apps>
2. **Create another app…** → name it `avwatch`, type **script**,
redirect URI `http://localhost:8080`
3. The ID is under the app name; the secret is the `secret` field.
```bash
setx AVWATCH_REDDIT_CLIENT_ID "your-id"
```
Free, and gives 100 requests/minute.
---
## Email setup
### Google Workspace
```toml
smtp_host = "smtp.gmail.com"
smtp_port = 587
use_starttls = true
username = "you@waterschurch.org"
```
Requires an **App Password** (Google Account → Security → 2-Step Verification →
App passwords). Your normal password will be rejected.
### Microsoft 365
```toml
smtp_host = "smtp.office365.com"
smtp_port = 587
use_starttls = true
username = "avwatch@waterschurch.org"
```
Two gotchas: with MFA you need an app password, and **SMTP AUTH is disabled by
default on new M365 tenants** — enable it in Exchange admin centre → the
mailbox → Manage email apps → tick *Authenticated SMTP*.
Test it without running a whole scan:
```bash
python -m avwatch test-email
```
---
## Automation
```bash
powershell -ExecutionPolicy Bypass -File scripts\install_tasks.ps1
```
That registers two per-user scheduled tasks (no admin rights needed):
| Task | When | What |
|---|---|---|
| **AVWatch Scan** | Tue / Thu / Sat 06:00 | Checks for new releases, refreshes the dashboard. Only asks Claude about versions it has never seen, so it is cheap. No email. |
| **AVWatch Digest** | Monday 07:00 | Full pass, every outstanding update gets a verdict, then the email goes out. |
Change the schedule:
```bash
powershell -File scripts\install_tasks.ps1 -ScanDays Monday,Wednesday,Friday -DigestTime 08:30
```
Remove them:
```bash
powershell -File scripts\install_tasks.ps1 -Remove
```
Run the digest right now without waiting for Monday:
```bash
python -m avwatch digest --dry-run
```
`--dry-run` builds everything and reports who it *would* mail, without
sending. Logs land in `logs\`, last 30 kept.
---
## The three inventory files
| File | Items | What it is |
|---|---|---|
| `inventory.yaml` | 86 | Everything from your original notes, plus the pieces those items require. Confirmed. |
| `inventory-expansion.yaml` | 116 | Categories your notes never mentioned — cameras, intercom, DMX nodes, projection, network core, UPS, click-track playback, storage. Either near-universal at this scale or directly implied by something you confirmed. |
| `inventory-optional.yaml` | 57 | Lower-confidence: common but genuinely optional. A checklist to skim. |
All `inventory*.yaml` files are loaded and merged automatically. **Deleting a
whole file is a supported action** — that is why the expansion lives separately
from your verified list.
### `status: unconfirmed`
130 of the added rows are marked `status: unconfirmed`. For those AVWatch runs
**no version lookup and gives no update advice at all**, and the `query` field
is deliberately empty.
That is not laziness, it is the safest available behaviour: a search built from
a guessed vendor returns a real, correct-looking version for the *wrong
product*, and the team then acts on it. Silence is better. Fill in the make and
model, set `status: confirmed`, and the row starts working.
### Update classes
Some rows are not a go/no-go decision at all:
- **`do_not_touch`** — fire alarm / voice-evac interface, rigging motors,
building automation. Licensed contractor only; a self-installed update can
void the listing that makes them compliant. Tracked for visibility, never
for action.
- **`vendor_pushed`** — YouTube, Resi's cloud platform, iPad apps, Stream Deck.
These update whether or not you approve. The useful signal is advance warning
of a breaking change, not a recommendation.
- **`expiry`** — CCLI, FCC Part 74, support contracts. These fail on a *date*,
not a version.
---
## How version detection actually works
This is the part worth understanding, because it determines what AVWatch can
and cannot tell you.
| Tier | Items | How | Reliability |
|---|---|---|---|
| `blackmagic` | 12 | Blackmagic publish their whole support catalogue as one JSON document. One fetch resolves ATEM, DeckLink/Desktop Video, HyperDeck, the converters and MultiView, with real release dates and release notes. | **High.** Verified working. |
| `github` | 6 | GitHub Releases API for OBS, Companion, Satellite, RustDesk, obs-websocket, DistroAV. Their issue trackers double as the best bug signal available. | **High.** Verified working. |
| `html` | 1 | Regex against the ProPresenter download page. | Medium — breaks if they redesign. The report will tell you. |
| `websearch` | 97 confirmed | Claude looks the version up with web search and cites the page it came from. | Medium. Guarded: it must return a source, low-confidence answers are downgraded to "check by hand", and answers are cached ~6 days. |
| `manual` | 29 | No field-updatable firmware exists — passive and analogue gear. Will never produce an update. | — |
| unconfirmed | 130 | No lookup attempted until you name the model. | — |
**Why so much `websearch`?** Because almost every AV vendor's support site is
now a JavaScript-rendered single-page app. Verified on 2026-09-08: Shure,
Resolume, Focusrite, Teradek, NovaStar, Line 6 and Rational Acoustics all
return HTTP 200 with essentially **no version text in the HTML**. A regex
scraper reads nothing from them. Gearspace and most vendor forums sit behind
Cloudflare and refuse scripted requests outright.
The design choice throughout is that **AVWatch never guesses a version it
cannot verify.** A confidently wrong version number would produce confidently
wrong advice, which is worse than an honest "go look at this page". So
anything unverifiable lands in a "check by hand" list with a link, and the
community bug scan still runs on it — which is arguably the half you cared
about most.
---
## What it costs to run
With an API key, per **weekly digest**. Note this scales with the *confirmed*
item count, not the 259 total — unconfirmed placeholders cost nothing:
- Version lookups: **97 confirmed items** needing the web lookup, cached 6 days,
on the cheaper model — roughly **$3–5**.
- Reasoning verdicts: only for items you are actually behind on, typically
10–25 — roughly **$0.50–2** on Opus.
So roughly **$4–7/week** at the current inventory size, with mid-week scans
nearly free because they reuse the cache and only ask about genuinely new
versions.
`lookup.max_items_per_run` is set to 120 to cover the confirmed set in one
pass. Lower it to cap spend — items over the ceiling are deferred to the next
run and the report says so explicitly rather than silently skipping them.
To cut cost further: set `model = "claude-sonnet-5"` under `[llm]`, raise
`lookup.ttl_days`, or delete `inventory-optional.yaml`. To spend nothing, run
`--no-llm` and you still get rule-based scores, coupling checks and the raw
evidence.
---
## Tuning the recommendations
`[policy]` in `config.toml` is where your judgement lives, and it matters more
than anything else:
```toml
soak_days_showstopper = 30 # a showstopper release must be 30 days old
soak_days_high = 21
soak_days_normal = 10
```
Raise these to get more conservative, lower them to move faster. Per item,
`criticality` in `inventory.yaml` picks which window applies — so **be honest
there**. Marking everything `showstopper` makes the report useless.
For gear you have deliberately decided not to touch:
```yaml
freeze: true
```
Frozen items are reported in their own section and never recommended. The X32
is a good candidate — mature firmware where the risk of touching it usually
exceeds the benefit.
---
## Commands
```bash
python -m avwatch doctor --network # check setup, test one fetch per source kind
python -m avwatch list # the tracked inventory
python -m avwatch scan # check for updates, write the dashboard
python -m avwatch scan --only obs-studio propresenter
python -m avwatch scan --offline # re-run from cache, no network
python -m avwatch digest # full pass + email
python -m avwatch report --text # rebuild from stored data, no network
python -m avwatch set-installed <id> <version>
python -m avwatch mark <id> holding --note "waiting for 10.5"
python -m avwatch history --item-id atem-constellation-4k
```
`mark` records what you decided, so there is a written history of who held what
and why — useful when the same question comes round again in three months.
---
## Things to fix in the inventory
Five entries could not be pinned down from the source list and are marked
`VERIFY` in `inventory.yaml`. They will not track properly until you name the
actual product:
- **DQ Rack** — ambiguous; Klark Teknik DN? Midas DL?
- **Quantum 225** — ambiguous; DiGiCo console? An amplifier?
- **DBOX+** — ambiguous
- **AJA devices** — the list said only "aja"; needs the model (KUMO, Ki Pro, HELO…)
- **Netgear Dante switch** — needs the model (M4250 / M4300 / …). Worth doing
first: it is the highest-consequence update in the fleet, because bad switch
firmware takes every Dante device down at once.
`Decimator` and `Focusrite RedNet` would also benefit from exact models.
---
## Limitations, stated plainly
- **It does not read your devices.** It compares "what you told us is
installed" against "what the vendor has published". Nothing is probed over
the network. Keeping `installed:` current is manual, and if it drifts, the
advice drifts with it.
- **Absence of bug reports is not safety.** The report says this out loud
rather than treating silence as a green light. Niche gear — NovaStar, RF
Venue, Decimator — has almost no community discussion, so verdicts there
rest mostly on release age and your policy.
- **Community posts are strangers on the internet.** AVWatch ranks and
summarises them; it does not vouch for them. Post text is passed to Claude
as untrusted data with explicit instructions never to follow instructions
found inside it.
- **`websearch` versions are web-sourced, not vendor-verified.** They are
labelled as such in the report.
- **No verdict replaces a rollback plan.** Nothing here knows whether you have
a spare, a saved show file, or a way back.