Files
LlamaCasty/docs/ai/environment.md
T
gramps a311c8feb1 docs(ai): partition ai.md into five subsystem files (verbatim moves)
ai.md 1,308 → 228 lines. No prose rewritten: every block was moved as-is so
nothing could be lost in translation, then replaced by a pointer.

New files:
- docs/ai/environment.md — LAN/SSH + Gitea push recipe, Windows dotnet
  build/run, test-suite map, hermetic real-MainWindow test rule
- docs/ai/product.md — brand/naming, AI transparency, GPL licensing
  prohibitions, free-forever monetization, auth/account assumptions,
  packaging & distribution
- docs/ai/youtube-api.md — go-live ordering, the broadcast-binding fix, the
  private-only lock, health parsing, end-stream pre-flight, Test mode,
  chat insert shape
- docs/ai/overlays.md — social bar, native alert box (animations, clip,
  ticker), chat box conventions
- docs/ai/ui-surface.md — control surface, scene strip, preview rail,
  hotkeys, broadcast drawer, toasts, transitions, brand logo, launch
  geometry, theme/properties conventions

ai.md keeps the response/derivation rules, the architecture table, the four
existing invariant stubs, and one pointer per moved subsystem.
docs/ai/index.md routes every file with a "read when" column.

References falsified by the move were fixed in the same commit: AGENTS.md
build note → environment.md → Run, and the "Related" footers in
frame-pipeline.md / output.md / capture.md now point at the owning files.

Docs-only unit: scope-check run, no build (no source touched).
2026-10-29 11:05:53 -07:00

141 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Environment, build & tests
Lookup material: LAN hosts, the Windows build commands, where the DB/auth/log live, and the
test suite map. Read when you are about to build, run, or add a test — not on every session.
> Paths and secrets belong with the runbook in [`../../HANDOFF.md`](../../HANDOFF.md) →
> "Secrets / paths" until the queue trim moves them here.
## LAN infrastructure (192.168.50.x)
All LAN credentials live in `CREDENTIALS.md` (gitignored). Server IPs and roles:
| Host | IP | Role |
|------|----|------|
| corsair | .132 | Gaming/streaming primary — RTX 5070 Ti (this machine) |
| llamavault | .87 | ODROID-HC4, 12TB RAID5, media storage (NFS). SSH: `ssh mshallop@192.168.50.87`. **DHCP-bound — it moved off `.86` after the 2026-10 power outage, so confirm with a ping before trusting any path.** SMB is reached by the **`llamavault` name**, pinned in the Windows hosts file, never by literal IP: `\\llamavault\llamaVault\...` |
| pivault | .158 | RPi5 8GB, 10.83TB RAID5 NAS |
| jarvis | .210 | AMD Ryzen 5 5600X, RX 6600 XT — AI inference, SearXNG, Docker registry, Immich |
| ultron | .108 | AMD Ryzen 7 7840HS — AI orchestrator, llama-server, Qdrant |
| gordito | .144 | Home Assistant, Alarmo, Zigbee |
| officerfriendly | .26 | Pi-hole DNS |
| octopi | .197 | OctoPrint (Prusa MK4) |
| BigBlinkyRouter | .1 | ASUS ROG GT-BE98 Pro, WiFi 7 |
Web infra (DO droplet): `llamacasty.com` + `llamachile.tube` at `143.244.176.131`.
**Pushing to the Gitea instance (`llgit.llamachile.tube`).** The repo is **`gramps/LlamaCasty`**
(renamed from `gramps/ytLlive`; the old path 301-redirects). **Push over HTTPS**, not SSH:
`origin = https://llgit.llamachile.tube/gramps/LlamaCasty.git`, with the credential helper
`/home/gramps/bin/gitea-credential` (registered as
`credential.https://llgit.llamachile.tube.helper`) reading the account password from the
gitignored `CREDENTIALS.md` on demand — nothing stored in plaintext, nothing in a command line.
**The Gitea account password IS the portal password** in `CREDENTIALS.md`, and the same password
authenticates the REST API (`curl --config …/api/v1/user`) — **that API is the fastest way to ask
the server questions** (the repo's real name and clone URL, the account's SSH keys, a token).
⛔ **The SSH endpoint on `llgit:2214` is not a usable push path**: the account's SSH keys ARE
registered (key id 6 "Corsair VSC" = this machine's `~/.ssh/id_ed25519`) yet the server refuses
the publickey, and the port later refused connections outright. Do not spend a session on key
archaeology — ask the API, then push over HTTPS.
## Run
**First time on a fresh clone (or if `ffmpeg/` was deleted) — this is REQUIRED, not optional:**
```bash
./scripts/fetch-ffmpeg.sh # ~65 MB once; verifies SHA-256, extracts 9 files into ./ffmpeg
```
FFmpeg is **bundled, never downloaded at runtime** (Windows Store policy 10.2.2 — the old runtime
download 404'd on 2026-09-01 and would fail certification). The binaries are gitignored because
135 MB of DLLs in git would tax every commit on this 9p tree; the pinned URL + SHA-256 in the script
are the audit trail. `ytLive.csproj`'s `GuardBundledFfmpeg` target **fails the build** with that
exact instruction if the folder is missing. `FFMPEG_ZIP=<path>` reuses a pre-downloaded archive.
```bash
# From WSL, ALWAYS use the Windows dotnet host — never Linux `dotnet` for this project:
"/mnt/c/Program Files/dotnet/dotnet.exe" build "C:\Users\gramp\Documents\Code\projects\ytLive\ytLive.csproj"
"/mnt/c/Program Files/dotnet/dotnet.exe" run -c Release # the launch command (creator, 2026-10-16): Release, not Debug — perf takes must read Release numbers
```
**Run-mode convention (creator directive 2026-10-16):** the creator launches with `-c Release`
by DEFAULT. Debug runs happen ONLY when the AI explicitly names the Debug command for a
specific reason — never implicitly, and never for reading performance numbers (Debug pixel
paths are several × slower; every take in the 141ms saga read Debug numbers where Release is
the real reading).
**Pre-commit gate (write it down — I forgot once):** ALWAYS run
`./scripts/verify.sh "<file1>" "<file2>" ...` (declared scope) before committing. It forces a
**clean** build (0 warnings), the full test suite (passes only the 2 known pre-existing `[FAIL]`s), and
the scope check in one shot. An **incremental** build can report `0 Warning(s)` while skipping
recompiles — that's how `CS8601` slipped past on 2026-08-29. Never claim 0 warnings from anything but
`verify.sh`'s clean build.
`EnableWindowsTargeting=true` in `ytLive.csproj` lets a cold restore work from WSL, but a Linux
`dotnet run`/`build` re-downloads 100M+ of `windowsdesktop.app.*` packs into the Linux NuGet cache
(which lacks them) over the slow 9p `/mnt/c` bridge — twice, because the WPF `_wpftmp` generated
project triggers a second restore (203s observed). The Windows cache has the SQLite packages and the
packs resolve from `C:\Program Files\dotnet\packs`, so the Windows host never re-downloads.
Never use `--no-restore` right after an interrupted restore — the stale `project.assets.json`
produces misleading `NETSDK1064` "package not found" errors. Running requires Windows anyway.
## Tests
xUnit in `ytLive.Tests` (net8.0-windows10.0.19041.0, matches the app TFM). Run on Windows —
WSL can't run net8.0-windows tests:
```bash
dotnet.exe vstest "C:\...\ytLive.Tests\bin\Debug\net8.0-windows10.0.19041.0\ytLive.Tests.dll"
```
Good Dog Rule: ONE integration test per change (no feature branches pre-1.0 — work lands on
`main`, see AGENTS.md). Current: TokenStore DPAPI
roundtrip/corrupt/missing/clear, OAuth exchange/refresh/ClearSession, CameraManager refcount +
frame pump + failure handling (fakes for the WinRT seams), real-`MainWindow` round-clip
interaction test, LayoutStore delete roundtrip, LayoutStore pre-round-rect-dims roundtrip,
LayoutStore background roundtrip, LayoutStore HasBackground roundtrip + v5→v6 non-Live backfill,
ScreenCaptureManager refcount + shared-bitmap + coalescing
(fake `IScreenCaptureSource` + a real background-STA `Dispatcher`), BackgroundTests, SceneCatalogTests,
the TASK 25 dirty-layout heal (BackgroundHealIntegrationTests), WebcamSafeguardTests,
SceneCompositorTests (full-scene composite + vertical tier), StretchMathTests, FfmpegLocatorTests,
FfmpegEncoderTests, FramePumpTests, the TASK 8/11/12 audio chain (AudioPipelineTests + MasterLimiter),
the Socials fediverse-heal roundtrip, AboutHubTests, NotificationAreaIntegrationTests (TASK 24),
GlobalHotkeyTests + HotkeyConfigTests (TASK 20), WebcamMenuGateTests (TASK 26), ChatLayerGateTests
(TASK 27), BroadcastPullOutTests (TASK 29), DefaultRecordFolder fallback (TASK 30), WebView2ManagerTests
(TASK 17), RecordingFileTests + OnAirSignTests (TASK 18), SessionTeardownTests +
WebcamOutputKeyTests + GameMeterHonestyTests (2026-09-01 recording-verification fixes) — **ZERO
known failures as of 2026-09-01. `AudioPipelineTests` 25/25 green in 26ms —
the "known failing" `Mix_HonorsProviderGains…` and the class's notorious STANDALONE HANG shared
one root cause: TASK 22's `_delayedMix` (nullable, never initialized) was dereferenced
(`delayed.Length` on null) every live-mix tick — a swallowed NRE starved the pipe the tests
read and flooded startup.log. Test was right, code drifted from the map's own contract
(loopbackGain = GameAudioVolume — now honored; the "unity because loopback scales with the
endpoint" assumption was disproven by the creator's 20%-volume meter observation). The former
RoundClip "known failure" (stale-test layers: namescoped `FindName` + `VisualTreeHelper.HitTest`
where `UIElement.InputHitTest` models input — see MyMistakes) was fixed the same day.
Per-class runs through the Windows dotnet.exe host execute the RealApp/MainWindow suites fine;
only the FULL-suite run still hangs (WASAPI teardown, pre-existing) — and the whole-suite
"247 total" era count is stale; trust per-class results.**
Reward-event capture (monetization awareness, see the Monetization section) will add its integration
tests here when it ships: one real chat-poll payload containing all seven reward event types →
assert the persisted canonical `RewardEvent` rows (type + amount/currency/tier/memberLevel/participant
ids) round-trip into SQLite.
### Real-MainWindow tests MUST be hermetic (DB pollution bug)
The integration test boots a real `MainWindow` → `MainViewModel` → real `LayoutStore`
(`%APPDATA%\ytLlive\ytLlive.db`). `Shutdown()` on close **saves the layout** (full rewrite:
DELETE all scenes/sources, re-insert), so any source a test adds would be persisted over the
user's real ones — this happened and wiped the real webcam source (DeviceId replaced by the
test's fake `test-camera`). Rule: a test that constructs `MainWindow` MUST first set
`MainViewModel.LayoutPathOverride` to a temp DB path and reset it (plus
`SqliteConnection.ClearAllPools()` + delete) in `finally`. The seam is
`internal static string? LayoutPathOverride` (line ~529 in `MainViewModel.cs`),
`ytLive.csproj` has `InternalsVisibleTo("ytLive.Tests")`.
The layout DB is a **full rewrite per save** (delete all, re-insert from memory), so
save/load round trips are exact: an element removed in the UI (`RemoveElement` →
`scene.Elements.Remove` → `OnElementsChanged` → debounced `ScheduleSave`, plus `Shutdown` on
close) does **not** come back after reload (`LayoutStorePersistenceTests` guards this).