Off-repo diagnosis (Pi 400, no RTC hardware, healthy crystal at -7.39 ppm): the box's clock sat ~43 h behind and systemd-timesyncd's first contact after the Oct 12 restart was 42.9 h later, so Pi-hole ran as a DNSSEC validator with a wrong clock -> 1.69M+0.84M dnssec=3 (BOGUS) rows on 10-11/10-12 hitting the PSN endpoints = the PS5's DNS errors. KSK-rollover theory retracted (both root anchors present; root DNSKEY still returns ad). Pending creator decision: tighten timesyncd polling and/or add a DS3231 RTC. MyMistakes: the reply marker string (recovered verbatim, with the search recipe), and the no-RTC/no-cron/timesyncd facts so the premise is not re-derived a third time.
143 lines
11 KiB
Markdown
143 lines
11 KiB
Markdown
# HANDOFF — 2026-10-17 (PLANNING ONLY session; nothing pushed — push at the next milestone)
|
||
|
||
## At a glance
|
||
- **Branch** main, tracking `origin/main`. **origin/main = `931ab46`; HEAD = the tip commit
|
||
"HANDOFF: vv webcam plan, and drop the stale vertical-preview landmine"** — **5 ahead, 0 behind**
|
||
(nothing pushed; per the commit/push policy, push only when the creator says so). This file cannot
|
||
record its own commit's hash, so the tip is named by subject.
|
||
- The five local-only commits: `3cb29ea` (previous session's HANDOFF refresh), `a3a4681`
|
||
(per-element composite timing + scene dump), `84cbec2` (FramePumpTests thread-safe log sink),
|
||
`cdf82f6` (read the first instrumented take), the tip. Always check
|
||
`git log origin/main..HEAD` — never trust a handoff's own "0 ahead" claim.
|
||
- Working tree clean after the tip commit.
|
||
- **This session produced NO code, NO build, NO test run.** It specified the creator's **vv
|
||
(vertical 9:16) webcam feature** end to end; implementation has not started. The locked rules are
|
||
below — they are the deliverable, and they must land in `TASKS.md` when work is queued.
|
||
The session's later half moved **off-repo** to the officerFriendly/Pi-hole/PS5 "DNS errors" diagnosis —
|
||
findings and the pending creator decision are in `Open (operational)` below.
|
||
|
||
## vv webcam feature — locked rules (creator, 2026-10-17)
|
||
| 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. Creator's explicit precedent, not an inferred one.
|
||
- **vv keeps its own camera position, size and shape per scene** — creator-confirmed: switching back
|
||
to 16:9 restores the desktop layout exactly as it was.
|
||
- **No explicit borderless/no-background mode is needed**: round + border/bg options already let the
|
||
creator strip both (creator's ruling — this deletes that item from the original request).
|
||
- Creator's "square" means the rectangular view (the camera's own aspect), not a literal 1:1 box.
|
||
|
||
## What the code already gives us (established this session — 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 creator's "two mini
|
||
16:9 views", each exactly 50% of the frame.
|
||
- **The Live webcam sits at x≈1425 → entirely outside the band.** That is the whole motivation: in vv
|
||
the camera is not misplaced, it is invisible.
|
||
- **Geometry only — no render-path change.** Preview (`Controls/PreviewPane.xaml` 144–230) and
|
||
compositor (`Services/Compositor/SceneCompositor.cs` 389–397, `DrawBorder`) both read the element's
|
||
own `X/Y/W/H` + `ClipShape`, so parking the camera needs no compositor or preview work. The
|
||
two-tile look *falls out of* the camera covering half the band — the capture element, chat box and
|
||
blit path stay untouched.
|
||
- **Round / border / background are independent**: `ClipShape.Round`; `HasBorder` = width > 0 AND a
|
||
valid 6-hex colour; `BackgroundEffect` = None/Remove/Blur.
|
||
- **Per-scene camera size policy already exists**: `MaxWebcamWidthFor/HeightFor` (Chat 1358×764,
|
||
others 960×540) + `ClampWebcamToBounds`. **A 607×540 tile sits inside both → the clamp needs no
|
||
change.**
|
||
- **Storage**: `WebcamSceneConfig` table; new columns go in `MigrateWebcamConfigTable()` as idempotent
|
||
`ALTER TABLE … ADD COLUMN` guarded on `PRAGMA table_info` — the established "additive, no version
|
||
bump" idiom (`RectWidth/RectHeight`, TASK 51's `BackgroundEffect` landed this way) — plus
|
||
`LayoutStore.Save.cs` INSERT and `LayoutStore.Load.cs` SELECT.
|
||
- **Existing per-element precedent for remembered geometry**: `RectWidth/RectHeight` +
|
||
`ToggleClipShape` (`Models/SceneElement.cs` 124–152) — the pattern for keeping the 16:9 layout
|
||
while vv owns its own.
|
||
|
||
## Units (each: ONE Good Dog integration test, own commit, memory in the same commit)
|
||
1. **vv camera layout** — 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:* 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.
|
||
2. **vv · Chat** — rect enforced with the circle option unavailable, plus enlarge-to-one-area
|
||
(607×540) snapping top or bottom.
|
||
*Test:* in Chat under the vertical tier, enlarge sets the full top area and the circle option is
|
||
not offered.
|
||
|
||
## Corrections made this session
|
||
- **Withdrawn landmine (creator-confirmed):** the old line "Vertical-format regression (STALE, not
|
||
fixed): 1080p60-vertical selection no longer shrinks the capture border in the preview" was **never
|
||
verified**, and it cost this session a pointless question. The creator confirms vv *does* dim the two
|
||
bands astride the centre band and that this is expected/best practice. If the original symptom was
|
||
something else (the capture element's own border?), it is **unexplained, not known-broken** — do not
|
||
re-raise it as a dependency.
|
||
- The prev-session content (first instrumented take: judder did not reproduce, no element slow; probe
|
||
+ recipe; the four local commits) is unchanged and lives in `ai.md` →
|
||
"✅ What the first instrumented take said".
|
||
|
||
## Next step
|
||
- **Implement Unit 1 on the creator's go-ahead.** Nothing is queued in `TASKS.md` — the creator queues
|
||
work, and this plan lives here until then. Queue it in `TASKS.md` as part of the first Unit 1 commit.
|
||
|
||
## Open (operational)
|
||
- **verify.sh's known-failure whitelist is too loose (confirmed twice on 2026-10-16):** it passes when
|
||
ANY known failure appears, so a new failure rides along unnoticed — and when the ONLY failure is a
|
||
known flake (`LayerReorderPersistenceTests.RealMouseDrag_OnTheLayerList_PersistsTheReorder`, which
|
||
passes in isolation) it reports "NOT the known pre-existing pair". **Follow-up: 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 it blindly).
|
||
- The judder reproduction take in the FAILING geometry (vertical 1080p60 first) is still outstanding —
|
||
**no fix until a take names the stage** (see `ai.md`; the `parts` line decides the latch hypothesis).
|
||
- ⛔ Sudo password rotation pending (user; then update both `CREDENTIALS.md` password lines).
|
||
- TASK 56 secret scan before `gramps/LlamaCasty` goes public.
|
||
- TASK 55 disk hygiene (`startup.log` uncapped — 23MB and the new lines add to it every 5s).
|
||
|
||
## Tests
|
||
- Last full run: **428/428 passed, 0 warnings** (2026-10-16, the gate run for `84cbec2`). **No run this
|
||
session (planning only).**
|
||
- Known flaky-by-environment (all pass in isolation): `AudioPipelineTests.Mix_HonorsProviderGains…`,
|
||
`MasterLimiter_CapsTheLiveMix_OnThePipe`, `LayerReorderPersistenceTests.RealMouseDrag…`,
|
||
`Round_Clip_Corner…`. **Read verify.sh's output — it can pass with an unlisted failure present, or
|
||
fail on a known flake (see above).**
|
||
|
||
## 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).
|
||
- Recordings land in `C:\Users\gramp\Downloads\recordings\` (`ty-<date>-<time>-<ms>-<seq>.mp4`; a
|
||
duplicate name gets a `-2` suffix — the log's path and the file on disk can differ that way).
|
||
- **Conversation history (how to recover what was actually said):**
|
||
`~/.local/share/opencode/opencode.db`, table **`session_message`** — creator turns are `type='user'`
|
||
with the text in `data.text`; my turns are `type='assistant'` with **reasoning AND the rendered reply
|
||
concatenated into `content[0].text`** (so my own reasoning quotes the creator's phrases — a `part` or
|
||
`data.text` hit may be my echo, not a real message). The **reply marker's verbatim string is recorded
|
||
in `MyMistakes.md`** (it was lost once and cost a session to re-derive).
|
||
- LAN credentials: `CREDENTIALS.md` (gitignored). 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 work)
|
||
- **Root cause found: a ~43 h-wrong system clock on officerFriendly × `dnssec = true`.** The box is a
|
||
**Pi 400 with no RTC hardware at all** (no `/dev/rtc*`, `hwclock` cannot open one, no `i2c-rtc`
|
||
overlay) and a **healthy oscillator** (`adjtimex` freq = −7.39 ppm = −0.64 s/day), so there is no
|
||
"dead RTC battery" — time comes from `fake-hwclock`'s saved file + `systemd-timesyncd`. The journal
|
||
shows the clock stepping forward **+54 min, +7 h, then +42.9 h** (last step Oct 14 13:56:44, the first
|
||
successful time-server contact after the Oct 12 19:01:43 restart). A validating resolver with a wrong
|
||
clock returns BOGUS, and `pihole-FTL.db` shows exactly that: **1,688,396 `dnssec=3` rows on 10-11 and
|
||
839,276 on 10-12 vs ≤23 every other day**, hitting `ps5.np.playstation.net` and the other PSN
|
||
endpoints = the PS5's "DNS errors". The KSK-rollover theory is **retracted**: both root anchors
|
||
(`20326` + `38696`) were already in place, and `dig @127.0.0.1 . DNSKEY` still returns `ad`.
|
||
- **Pending creator decision (do not apply unilaterally):** tighten
|
||
`/etc/systemd/timesyncd.conf.d/lan.conf` (currently IP-literal NTP servers = Cloudflare + Google, but
|
||
stock poll settings) to `PollIntervalMinSec=16` / `PollIntervalMaxSec=64` / `ConnectionRetrySec=8` /
|
||
`SaveIntervalSec=30`, and/or give the Pi a DS3231 RTC on i2c (`i2c-tools` is already installed).
|
||
- **LAN DNS routing vs creator intent:** DHCP still hands out `dhcp_dns1_x = 192.168.50.26` +
|
||
`dhcp_dns2_x = 192.168.50.1` (clients query Pi-hole **directly** — 37 distinct LAN nodes in 24 h, 41
|
||
including the router), whereas the creator wants everything to point at `.1` with BBR forwarding to
|
||
Pi-hole (`wan_dns = 192.168.50.26` already works: `.1` made 3811 queries). Also `dnssec = true` on
|
||
Pi-hole duplicates dnscrypt-proxy's `require_dnssec = true`. Both are offered-for-veto, not yet done.
|