Files
LlamaCasty/HANDOFF.md
T

28 KiB
Raw Blame History

HANDOFF — 2026-10-22 (the creator's properties-panel asks shipped, incl. TASK 63, and pushed; the vv webcam Units 1+2 state below)

At a glance

  • Branch main, tracking origin/main. The six-commit properties-panel batch is PUSHED (2026-10-22, as a sub-milestone): TASK 58 the theme sweep, TASK 59 the properties hierarchy, TASK 60 the colour names, a docs commit, TASK 61+62 the geometry field widths and the colour name beside the hex, and TASK 63 the border-colour picker as the app's own drop-down — the creator's properties-panel asks, done in one batch. origin/main is now 987fdda.
    • The vv feature (Units 1+2) was pushed at its close (2026-10-21 — the creator approved the Unit 1 push after testing it, and the completed feature is a milestone).
    • The push path changed: origin is now https://llgit.llamachile.tube/gramps/LlamaCasty.git (HTTPS + the credential helper /home/gramps/bin/gitea-credential, which reads the password from the gitignored CREDENTIALS.md; plain git push works). The old SSH remote was broken twice over: the repo was renamed gramps/ytLlive → gramps/LlamaCasty, and llgit:2214 refuses the publickey of this machine's key even though it IS registered (account key id 6 "Corsair VSC"). Ask the Gitea REST API, don't do key archaeology — recipe in MyMistakes.md → 2026-10-21.
  • This session shipped vv webcam Units 1+2 (the vertical 9:16 tier keeps its OWN camera placement per scene; 16:9 restores the desktop layout exactly; the Chat scene in vv is rect-only and can be enlarged to fill a whole 607×540 area). Code + memory in ONE commit each; the ONE Good Dog tests are ytLive.Tests/VerticalWebcamLayoutTests.cs (Unit 1) and ytLive.Tests/VerticalChatCameraLayoutTests.cs (Unit 2). Only the creator's hands-on check is left — see the vv section.
  • TASK 58 — the properties panel now wears the theme (shipped 2026-10-21). The creator's "why is the drop-down not in the same style as the others?" was a real defect: those drop-downs (and every check box, and every properties field) had been hand-painted with a Background/ Foreground instead of a style, so WPF drew the light system template on top of the dark panel. Now: ComboBox → YtComboBox, CheckBox → YtCheckBox (new), properties fields → YtTextBoxCompact (new, BasedOn YtTextBox). Guard: ytLive.Tests/PropertiesStyleTests.cs.
  • TASK 59 — the properties panel is a hierarchy (shipped 2026-10-21). A title owns its content and the content is indented one level (10px): Shape (new title) over the Mirror switch and the shape choice, the drag hint indented under that row, Geometry / Border Color / Border Thickness as titles with their fields indented, Background's Remove + Blur indented, and Strength one level deeper under Blur. The shape became a CHOICE: Rect | Circle as two segment options with Rect selected by default (the old single button showed the next action, "Round"). The mutual exclusion lives in the model (IsRectShape/IsRoundShape on SceneElement) — a WPF RadioButton group would kill the bindings. Guard: ytLive.Tests/PropertiesHierarchyTests.cs.
  • TASK 60 — the border-colour drop-down names every colour (shipped 2026-10-21). The creator: "the #hex values are good, but add a corresponding color name/label next to the value" — each row now reads #e94560 Crimson (the name dimmed, the tooltip "Crimson (#e94560)"). The 14 colours moved out of the click handler into Models/BorderColorPalette.cs (NamedColor(Hex, Name) + NameOf(hex)), so the list is testable and extensible. Guard: ytLive.Tests/BorderColorPaletteTests.cs.
  • TASK 61 + 62 — the geometry fields and the border-colour field (shipped 2026-10-21).
    • 61: the X/Y/W/H fields share ONE fixed width (44px — the largest geometry value, 1920, plus a sign) and their rows set LastChildFill="False", so Y/H no longer stretch to fill the row while X/W sized themselves to their text. Guard: ytLive.Tests/GeometryFieldWidthTests.cs (it MEASURES the widest value with WPF's FormattedText — measure, don't guess).
    • 62: the border-colour field shows the palette's name beside the hex (SceneElement.BorderColorName, empty for a custom hex), and the hex field keeps a fixed width so the name stays next to the hex. The field stays editable (a custom hex can still be typed). Guard: ytLive.Tests/BorderColorNameTests.cs.
  • TASK 63 - the border-colour picker IS the app's drop-down (shipped 2026-10-21; popup click deselection fixed 2026-10-22). The creator: "why does the drop down under the web cam properties not show the same style for the border color drop down list box?" and "we established look-and-feel standards. And yet you keep ignoring these and I'm wondering why." Root cause of the miss: the TASK 58 sweep looked for control types (ComboBox/CheckBox/TextBox) without a theme style - and the border picker was NONE of those: it was a ... Button whose Click handler built a ContextMenu in code. It was never in the sweep's scope, and PropertiesStyleTests.cs (a type-based guard) could not see it either. Now: the picker is a YtComboBox bound to the palette (SelectedElement.BorderColorOptions / BorderColorEntry), the closed box shows the swatch + the colour's NAME, the rows show swatch + hex + name, the hex field stays for a custom colour, the swatch is painted by the theme's HexToBrush converter, and the hand-built menu + WebcamBorderColorPicker_Click are gone. The closed box != the rows only through Helpers/ClosedBoxTemplateSelector.cs (WPF copies ItemTemplate into the read-only SelectionBoxItemTemplate; the selector is told them apart by the ContentPresenter's templated parent - ComboBox = closed box, ComboBoxItem = a row). 2026-10-22 creator bug fix: clicking a colour in the open ComboBox popup registered as an exit from the properties listing because LeftPanel.IsDescendantOf used child is Visual ? VisualTreeHelper.GetParent(child) : LogicalTreeHelper.GetParent(child) — at PopupRoot (which IS a Visual), VisualTreeHelper.GetParent returns null, so IsDescendantOf stopped without crossing PopupRoot's logical parent (PART_Popup → ComboBox → ElementsScrollViewer), and MainWindow.Window_PreviewMouseLeftButtonDown cleared SelectedElement = null. Fixed by falling back to LogicalTreeHelper.GetParent / TemplatedParent when VisualTreeHelper.GetParent returns null. Guard: ytLive.Tests/BorderColorPickerTests.cs (model + panel + the real widget, including LeftPanel.IsClickInside on an open popup row and clicking a row to change BorderColor). The TASK 60 guard (BorderColorPaletteTests) was updated to guard the new wiring (the drop-down is bound to the palette; no second list of colours anywhere).
  • TASK 55 slice 1 — the log is capped (shipped 2026-10-22). startup.log was uncapped (23 MB and growing every few seconds — ffmpeg logs every stderr line). Now it rolls to startup.1.log at 5 MB (one rolled copy kept), so the growth is bounded. The policy is Helpers/LogRotation.cs (a pure function over a path — AppLog's 156-call-site surface is unchanged; the seams are two internal properties). Guard: ytLive.Tests/AppLogRotationTests.cs. Slices 2 (temp alert-clip cleanup) and 3 (low-disk guard before recording) are still open.
  • TASK 48 slice 2 — the app PACKS as a Store MSIX (shipped 2026-10-22). Packaging/Package.appxmanifest (full trust: Windows.FullTrustApplication + uap10:TrustLevel=mediumIL + uap10:RuntimeBehavior=packagedClassicApp + rescap runFullTrust, plus webcam/microphone DeviceCapabilitys, x64, en-US only) + Packaging/Assets/ (four logo tiles generated from the app's own artwork by scripts/make-store-logos.py) + scripts/package-msix.sh (publish Release -r win-x64 --self-contained → stage → makeappx pack, optional MSIX_PFX signing). First real package built: artifacts/LlamaCasty.msix, 159 MB, 509 files, Package creation succeeded (artifacts/ is gitignored). Guard: StorePackagingTests.The_package_manifest_declares_full_trust_camera_and_microphone. ⚠️ Before submission the manifest's Identity/@Publisher and PublisherDisplayName must be set to the exact values Partner Center shows — a mismatch is a rejection.
  • TASK 48 slice 3 — the self-updater is gone (shipped 2026-10-22). The Store route (creator ruling 2026-09-27) means the Store updates the app, so the Velopack package + bootstrap were deleted (ytLive.csproj, App.xaml.cs) — a compliance action, not cleanup: the updater downloaded and executed, which Store policy 10.2.2 does not permit. The DO update-URL droplet dies with it. Guard: ytLive.Tests/StorePackagingTests.cs (no updater package, no updater API in any app source file). The app was smoke-tested after the removal: MainWindow loaded, no exceptions. Still open on TASK 48: slice 2 (the Package.appxmanifest + packaging project), slice 6 (the full-trust recording invariant comment), slice 7 (disqualifier re-check), slice 8 (the pre-submission gates) — and slices 4/5 are the creator's (Certification Kit, Partner Center listing, the demo account).
  • The previous session (HA lights) produced NO ytLive code — it was spent on the creator's Home Assistant light alert system (off-repo, 192.168.50.145). See MyMistakes.md → 2026-10-21: the plan was one tweak to a verified-working script; the script was rewritten twice, the alert path broke, and the day was burned. The HA work landed OK in the end (recipes + measurements now in MyMistakes.md). Records below so the next session does not re-hunt.

HA light alert system — current, verified state (2026-10-21)

Five Tapo bulbs: light.br1, light.br2, light.officeone, light.officetwo, light.death_star_light. Purpose: the creator is deaf — lights are the alert channel; the phone (notify.mobile_app_mis_lx9) is secondary. The iPhone is gone — never notify it.

State br1 / officeone br2 / officetwo Death Star
Idle off off off
Pump running off off blue only (creator directive)
Leak warm-white 100% purple purple
Alarm warm-white 100% red red
Doorbell green, 8s green, 8s green, 8s
Doorbell during an alert — suppressed — —
Clear off off off

Architecture: script.alerts_arm / alerts_clear write only input_text.light_alert (none|leak|alarm|motion, restart-surviving). script.alerts_render_lights is the single writer of the bulbs — flat top-level if/else blocks (nested if and choose: both silently lit nothing; do not "improve" the shape). Priority: an alert always beats pump status.

⛔ THE ENTITY-ID TRAP (cost this session hours): the YAML key is alerts_render but the entity id is script.alerts_render_lights. script.turn_on on a non-existent entity returns HTTP 200 and does nothing — no error, no log. All callers now use the _lights id. Check this first on any "script does nothing" symptom.

Pump status is a status, not an alert (auto-clearing), and is keyed off sensor.water_pump_current_consumption — never switch.water_pump_2, which was observed latched on for hours at 0.0A draw and painted the bedroom blue at 5am.

HA files touched (/config, root-owned → writes need sudo): scripts.yaml, automations.yaml, configuration.yaml (added input_text.light_alert / _prev). Backups: scripts.yaml.bak-alertbuild, automations.yaml.bak-alertbuild, automations.yaml.bak-notify-20261020, configuration.yaml.bak-tplinkfix. Zombie entities deleted from the registry: script.leak_strobe, script.doorbell_flash (old one), automation.leak_strobe_notify_clear_restore, script.alerts_render_lights_2. Leak sensor is healthy (binary_sensor.pump_leak_moisture = off, battery 100, signal 3) — an earlier "unavailable" claim was a bad read during a reload; alert_leak_on now also triggers on the latched sensor.pump_leak_last_water_leak_alert.

vv webcam feature — locked rules (creator, 2026-10-17) — Units 1+2 shipped 2026-10-21

mode shape size position
16:9 as today as today as today
vv · Live circle OR rect, creator's choice small tile one of six spots: top/bottom × L/C/R
vv · Chat rect only — no circle option normal, or enlarged to fill one area (607×540) enlarged → top or bottom
Starting / BRB / Ending unchanged unchanged unchanged
  • Placement is set by tap/click-drag with snap, exactly like the socials today, plus manual entry in properties. vv keeps its own camera position, size and shape per scene — switching back to 16:9 restores the desktop layout exactly.
  • No explicit borderless/no-background mode is needed (round + border/bg options already allow it).
  • Creator's "square" means the rectangular view (the camera's own aspect), not a literal 1:1 box.

What the code already gives us (do not re-hunt)

  • vv = the active tier's centred band crop. 1080p60-vertical: master band x 656.25–1263.75 (607.5 wide), full height, upscaled to 1080×1920 (MainViewModel.Streaming.cs ApplyStreamQuality → OutputRect*). The band splits into two 607×540 areas (top/bottom).
  • The Live webcam sits at x≈1425 → entirely outside the band — in vv it is invisible. That is the whole motivation.
  • Geometry only — no render-path change. Preview (Controls/PreviewPane.xaml 144–230) and compositor (Services/Compositor/SceneCompositor.cs 389–397) both read the element's own X/Y/W/H + ClipShape.
  • Round / border / background are independent: ClipShape.Round; HasBorder = width > 0 AND valid 6-hex colour; BackgroundEffect = None/Remove/Blur.
  • Per-scene camera size policy exists: MaxWebcamWidthFor/HeightFor (Chat 1358×764, others 960×540)
    • ClampWebcamToBounds. A 607×540 tile sits inside both → no clamp change.
  • Storage: WebcamSceneConfig table; new columns via MigrateWebcamConfigTable() as idempotent ALTER TABLE … ADD COLUMN guarded on PRAGMA table_info + LayoutStore.Save.cs INSERT and LayoutStore.Load.cs SELECT.
  • Precedent for remembered geometry: RectWidth/RectHeight + ToggleClipShape (Models/SceneElement.cs 124–152).

What shipped in Unit 1 (2026-10-21) — do not re-hunt

  • Geometry only — NO render-path change. The tier switch swaps the element's LIVE geometry; the preview and the compositor read X/Y/W/H + ClipShape exactly as before.
  • Models/VerticalCameraLayout.cs (new): the pure math — band x 656.25, w 607.5, h 1080; two 607×540 areas; six spots; default tile 270×152 master px (= 480×270 in the 1080×1920 output), bottom-right spot; inset 32 master px.
  • Models/WebcamSceneConfig.cs: the vertical placement is persisted in seven additive columns (VerticalX/Y/Width/Height/VerticalClipShape/VerticalRectWidth/VerticalRectHeight, NULL = "this scene has no vertical placement yet"); the 16:9 layout stays in the old columns and is parked in the transient Landscape* fields while the vertical tier is live. BeginVerticalLayout / EndVerticalLayout / CommitLiveLayoutToVertical do the swap.
  • Models/SceneElement.cs: X/Y/Width/Height are now virtual so the webcam clamps EVERY write (drag, resize, typed fields) into the band — outside the band = invisible in vv.
  • ViewModels/MainViewModel.Webcam.cs: IsVerticalTier/VerticalBand + ResolveVerticalCameraLayouts (the tier swap; the Live scene gets its tile automatically on the first vertical switch) + MoveWebcamInVerticalTier/SnapWebcamInVerticalTier (the six-spot snap, by the tile's CENTRE). MainViewModel.Streaming.cs ApplyStreamQuality is the tier-change hook.
  • Controls/LeftPanel.xaml: the webcam properties gained a Geometry section (X/Y/W/H) bound to the live placement, gated on the VM's IsWebcamSelected (NOT SelectedElement.IsWebcam — the TASK 51 test finds that panel by binding text and would match twice).
  • Controls/PreviewPane.xaml.cs: dragging/resizing a webcam under the vertical tier routes through the VM's snap instead of free-floating over the master.
  • Test seam: the drag lives in a VM method, so the test drives it without synthesising mouse input.

What shipped in Unit 2 (the Chat scene, 2026-10-21) — do not re-hunt

  • Rect only, and the lock is on the MODEL, not the UI. WebcamSceneConfig.VerticalShapeLocked (set per scene by the VM) overrides the ClipShape property → a locked camera cannot become Round by any writer (the toggle, the Shape button, the placement swap). SceneElement.ClipShape and SceneElement.ToggleClipShape() are virtual for this. The lock is cleared before the 16:9 layout comes back, so the desktop shape is restored.
  • The circle is not OFFERED: MainViewModel.CanToggleClipShape is false for a Chat camera in the vertical tier → the Shape button in the webcam's properties disappears (not just disabled). MainViewModel.cs raises it on the selection change; MainViewModel.Streaming.cs on the tier change.
  • Two sizes, snapped by the nearer one: VerticalCameraLayout.SizeFor(band, requestedWidth) → the small tile (270×152) or one whole area (607.5×540). The resize handle therefore has two detents instead of any size in between.
  • An enlarged camera fills the area its centre is in — top or bottom (VerticalCameraLayout.AreaFor).
  • The Chat camera is auto-tiled like the Live one when the vertical tier is picked (otherwise the vertical chat stream has no camera at all). ResolveVerticalCameraLayout now auto-tiles Live and Chat; Starting/BRB/Ending keep their 16:9 placement.
  • The preview's resize routes through MainViewModel.ResizeWebcamInVerticalTier (the Chat camera's discrete size + the snap); the drag routes through MoveWebcamInVerticalTier (assign → clamp → snap, so the enlarged camera can be dragged from the top area to the bottom one).
  • Test: ytLive.Tests/VerticalChatCameraLayoutTests.cs — PASSES (in Chat under the vertical tier, enlarging fills the full top area and the circle option is not offered).

Units (each: ONE Good Dog integration test, own commit, memory in the same commit)

  1. ✅ vv camera layout (Unit 1) — shipped 2026-10-21. Stored separately per scene, resolved when the tier changes. Live: small tile (circle or rect) snapped to one of six spots; drag like the socials + properties entry. Test: ytLive.Tests/VerticalWebcamLayoutTests.cs — with the vertical tier active, dragging the Live camera to top-right places it top-right inside the band; switching back to 16:9 restores the original layout exactly; both placements survive a save + reload. PASSES.
  2. ✅ vv · Chat (Unit 2) — shipped 2026-10-21. Rect enforced with the circle option unavailable, plus enlarge-to-one-area (607×540) filling the top or the bottom area by where the camera is. Test: ytLive.Tests/VerticalChatCameraLayoutTests.cs — in Chat under the vertical tier, enlarge sets the full top area and the circle option is not offered. PASSES.

Next step

  • ✅ TASK 63 + popup-click fix verified by creator (2026-10-22) — clicking a colour in the Border Color YtComboBox dropdown now stays inside LeftPanel (IsDescendantOf crosses PopupRoot → PART_Popup via LogicalTreeHelper.GetParent), updates the webcam border colour, and does not exit the properties listing.
  • Creator check (needs the creator's hands) — the last piece of the vv feature: switch the resolution dropdown to "Vertical 1080p60", confirm the Live camera tile lands inside the band and the Circle option (TASK 59 turned the Shape button into a Rect | Circle choice) turns the tile into a circle there, open the Chat scene and confirm the Circle option is gone (rect only) and that dragging the tile up and enlarging it fills a whole 607×540 area, then switch back and confirm the desktop layout is untouched. The unit tests cover the geometry, not the eyeball.
  • Nothing else is queued for llamacasty — the creator queues work.

Open (operational)

  • Follow-up (not fixed — out of scope for TASK 61): the web source block's geometry rows in Controls/LeftPanel.xaml (the SelectedElement.IsWebSource panel, ~lines 387-402) have the identical shape and the identical defect as the webcam's did — the Y/H fields stretch to fill the row. Same one-line-per-field fix as TASK 61, when the creator wants it.
  • ✅ FIXED in TASK 63: the border-colour swatches now carry a 1px BorderBrush="#2a3a5e", so the black (#000000) and dark swatches are visible against the dark menu (#16213e).
  • Follow-up spotted while doing TASK 63 (not fixed — out of scope for that change): the theme has no implicit Button style, so every plain <Button> in the app still renders with the light WPF system template (Controls/LeftPanel.xaml ×7, Controls/CameraPickerDialog.xaml ×2). The border picker's ... button was one of them and is gone; the rest are still there. A theme-level implicit Button style would fix them all at once — that is a creator-queued task, not a silent edit.
  • GOG Galaxy launcher shows "offline" (2026-10-21) — GOG's own overnight outage, NOT Windows. GOG put www.gog.com behind a maintenance page (503) and their Fastly services for auth.gog.com / api.gog.com / remote-config.gog.com return 500 "Fastly error: unknown domain"; the page itself says "Galaxy Launcher will also be down." Window: 00:00–08:11 local on 2026-10-21 — the Wayback snapshot of www.gog.com/en/ at 06:56 UTC is HTTP 200 with the full live storefront. status.gog.com is NXDOMAIN globally. Local exoneration chain: genuine GOG sp. z o.o → DigiCert cert (no MITM), local DNS == Google's authoritative answers, real Fastly POP headers, and GOG's own non-Fastly servers still answering. Nothing to fix locally — wait for GOG. Galaxy's logs (incl. the rotated ones) show no API-status failures between Oct 10 and Oct 20. Diagnosis recipe + the webfetch-is-not-an- independent-egress trap: MyMistakes.md → 2026-10-21 GOG Galaxy "offline". Galaxy 2.0 logs live in C:\ProgramData\GOG.com\Galaxy\logs\ (NOT %LOCALAPPDATA%). ⚠️ that folder also holds a 2.7 GB cef.log (since Jul 13) — disk hygiene, see TASK 55.
  • verify.sh's known-failure whitelist is too loose (confirmed twice 2026-10-16): require EVERY failure line to be whitelisted, and add MasterLimiter_CapsTheLiveMix_OnThePipe + RealMouseDrag_OnTheLayerList_PersistsTheReorder to the list.
  • A pre-existing stash is still sitting there: stash@{0} = "WIP on main: 0464593 Compositor: fast-path opaque 1:1 when source fills canvas" (NOT this session's; do not drop blindly).
  • The judder reproduction take in the FAILING geometry (vertical 1080p60 first) is still outstanding — no fix until a take names the stage.
  • ⛔ Sudo password rotation pending (user; then update both CREDENTIALS.md password lines).
  • ✅ TASK 56 secret scan — DONE 2026-10-22, CLEAN. 432 reachable commits (all branches, 35 tags, reflog, stash) + 63 dangling commits + the worktree: 0 real secrets. 4 rule hits, all false positives (README.md:79 = the your-client-secret doc placeholder; TokenStoreTests.cs:22 = a 9-char test dummy). CREDENTIALS.md/MARCOM.md/ Helpers/OAuthCredentials.cs were never tracked. ⚠️ the repo was already public (anonymous GET → 200, API private = false) when the scan ran — the gate came late, but nothing leaked. Method + verdict: TASKS/task-56-secret-scan.md.
  • TASK 55 disk hygiene: slice 1 (log rotation) shipped 2026-10-22 — see the At-a-glance bullet. Slices 2 (temp alert-clip cleanup) + 3 (low-disk guard before recording) are open. (The GOG Galaxy cef.log at 2.7 GB is NOT ours.)

Tests

  • Last full run: 438/438 passed, 0 warnings (2026-10-22 — after TASK 48 slice 2's manifest guard; the run before was 437/437 after slice 3's StorePackagingTests, then 436/436 after TASK 55 slice 1's AppLogRotationTests and 435/435 after TASK 63). The one failure seen earlier in the session was LayerReorderPersistenceTests.RealMouseDrag_OnTheLayerList_PersistsTheReorder, which passes in isolation (re-run: 3/3) — the known real-mouse flake, not a regression.
  • Known flaky-by-environment (all pass in isolation): AudioPipelineTests.Mix_HonorsProviderGains…, MasterLimiter_CapsTheLiveMix_OnThePipe, LayerReorderPersistenceTests.RealMouseDrag…, Round_Clip_Corner….
    • ⚠️ LayerReorderPersistenceTests.RealMouseDrag_OnTheLayerList_PersistsTheReorder is NOT "passes in isolation" any more. During this session it FAILED ALONE on a clean tree at 58b9a7d (the vv work stashed) with the same "Expected: ImgC / Actual: ImgA" — i.e. it is an environment/real-mouse flake, not a regression from the vv work — and it PASSES in the full-suite run (429/429). Treat it as environment-dependent, and don't chase it as a regression without stashing first.

Secrets / paths (do not re-hunt)

  • Layout DB: %APPDATA%\ytLlive\ytLlive.db (SQLite, full-rewrite per save). Auth: %APPDATA%\ytLlive\ytLlive.auth (DPAPI). Startup log: %APPDATA%\ytLlive\startup.log (23MB — now CAPPED at 5 MB with one rolled copy, TASK 55).
  • Recordings land in C:\Users\gramp\Downloads\recordings\ (ty-<date>-<time>-<ms>-<seq>.mp4; a duplicate name gets a -2 suffix).
  • Conversation history: ~/.local/share/opencode/opencode.db, table session_message — creator turns are type='user' with text in data.text; my turns are type='assistant' with reasoning AND the rendered reply concatenated into content[0].text. The reply marker's verbatim string is recorded in MyMistakes.md.
  • LAN credentials: CREDENTIALS.md (gitignored) — ⚠️ stale for HA: it says 192.168.50.144, the real Home Assistant is 192.168.50.145 (homeassistant.local, HAOS 18.2, Core 2026.10.1, SSH gramps/einstein, /config root-owned). gordito is .144. Fix this file when next editing it.
  • Google Cloud OAuth project number 198374416003, owned by llamachile.shop@gmail.com — verify at https://console.cloud.google.com/apis/credentials?project=198374416003.

Open (operational) — officerFriendly / PS5 "DNS errors" (2026-10-17, off-repo)

  • Root cause: a ~43 h-wrong system clock on officerFriendly × dnssec = true. Pi 400, no RTC hardware at all, healthy oscillator (−7.39 ppm). Journal shows +54 min, +7 h, +42.9 h steps. pihole-FTL.db: 1,688,396 dnssec=3 rows on 10-11, 839,276 on 10-12 vs ≤23 other days, hitting PSN endpoints = the PS5's "DNS errors". KSK-rollover theory retracted.
  • Pending creator decision (do not apply unilaterally): tighten /etc/systemd/timesyncd.conf.d/lan.conf to PollIntervalMinSec=16 / PollIntervalMaxSec=64 / ConnectionRetrySec=8 / SaveIntervalSec=30, and/or add a DS3231 RTC (i2c-tools already installed).
  • LAN DNS routing vs creator intent: DHCP still hands out .26 + .1 (clients query Pi-hole directly) whereas the creator wants everything → .1 with BBR forwarding. Also dnssec = true on Pi-hole duplicates dnscrypt-proxy's require_dnssec = true. Both offered-for-veto, not done.
  • Router is the DHCP server (ASUS ROG GT-BE98 Pro .1) — Pi-hole .26 is DNS only, its dhcp.leases is 0 bytes.