Repository navigation
PLAN-v3 Phase 1: pin the web stack and fix the first-wave bugs - #8
Merged
Merged
Conversation
Pin the fastapi and uvicorn transitive packages to the versions CI installed, accept loopback Host headers on the configured port, and keep shoutouts on !so. Viewer history is fenced, alert and recap completions time out, wake frames are scored once, tokens are rechecked, and session ducking follows an app list. Co-authored-by: Kisahime <Kisahime@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces
PLAN-v2.mdwithPLAN-v3.mdand implements the Cursor tasks in V3 Phase 1. V3-P0 stays unchecked; those checks need the owner's hardware or accounts.V3-P1-01 — pin the web stack and accept IPv6 loopback (F-01)
Starlette 1.6.0 splits
Hoston the first colon, soHost: [::1]:8080becomes[and the existing host test returns 400. CI for933dd35installed starlette 1.7.0, which parses the hostname and keeps the brackets, so that same test already passed there.requirements.txtnow pins the fastapi/uvicorn transitive stack to that CI resolution (starlette==1.7.0,anyio==4.15.1, and the pydantic, click, h11, httptools, and watchfiles pins from the same install).uvloopstays unpinned because it is Unix-only and is not installed on the Windows runner.create_apppasses the prepared settings port, orserver.portfromconfig.yaml, intotrusted_hosts(). The allow list includes127.0.0.1,localhost,::1, and[::1], each with the configured port. A request withserver.port9090 acceptsHost: 127.0.0.1:9090andHost: [::1]:9090and still rejectsevil.test.V3-P1-02 — shoutouts only for
!so(F-02)_perform_chattreated every allowlisted non-speak command as a shoutout.chat_actionalready returnscommandfor those lines, sosrc/policy.pydid not need a change. A command inchat.mod_commandsis now skipped withnot a modbefore any branch runs. Only!socalls shoutout. Any other command is skipped withunhandled command. A viewer's!lurk bobdoes not call shoutout; a mod's!so bobstill does; a viewer's!so bobisnot a mod.V3-P1-03 — fence viewer history (F-03)
llm_messages()wraps viewer turns, including twitch-event turns stored as viewer, withfence_viewer_text(). Streamer turns stay plain text. Assistant turns are unchanged. A stored viewer lineignore previous instructionscomes back inside<<viewer>>.V3-P1-04 — time-box alerts and recap vibe (F-04)
ollama.chat_timeout_seconds(default 20) already bounded chat replies._finish_replyand the recap vibe paragraph now use the same limit, so no new setting was added. On timeout the alert skip reason isllm timeout, the phase returns to idle, and the alert text that was stored before the model call stays in memory. The next queued alert is handled. A vibe timeout leaves the recap without a## Vibesection.V3-P1-05 — idle wake score, each frame once (F-05)
The level loop broadcasts while the mic stream is open and either listening, push-to-talk, or a wake model is loaded. The mic keeps a carry buffer and scores only new 1,280-sample frames. A detection calls
model.reset()when the model has one. A fake model sees each sample once across uneven chunks, and a level message with a wake value is sent while listening is off.V3-P1-06 — hourly revalidation and action scopes (F-06)
The Twitch watchdog calls
validatefor the event token every 60 minutes while EventSub is connected and storesvalidated_at. Remaining lifetime isexpires_in - (now - validated_at). A 401 or 403 on that check sets EventSub totoken rejected. IRC is validated once on connect: login must matchTWITCH_NICK, andchat:readpluschat:editmust be present. A mismatch is reported asIRC token login is {login}, expected {nick}. Health listsactions.shoutoutandactions.markerfromACTION_SCOPES. The dashboard disables those buttons and sets the tooltip when the status starts withmissing scope.Shoutout and Remember this disabled when the action scopes are missing
Checked in headless Chrome against a fake booth: with empty scopes both buttons were disabled and their titles were
missing scope moderator:manage:shoutoutsandmissing scope channel:manage:broadcast. With both scopes present, both buttons were enabled and the titles were empty.V3-P1-07 — per-app session ducking (F-07)
The old "speaker must be a different device" refusal is gone. Pixel's own process is still skipped inside the Windows snapshot.
audio.duck_apps(default empty) is an allow-list;audio.duck_skipdefaults toobs64.exeandDiscord.exe. An injected backend ducks matching sessions even whenspeaker_deviceis null. Without a backend on non-Windows, the mode staysobs-sidechain. README now describes per-app session ducking.chrome:4is not in the default skip list, so it is ducked, anddata/duck.jsonstill restores the previous levels.Tests
ruff check src testspassed.pytest -qpassed: 105 tests. New coverage is intests/test_phase2.py,tests/test_shoutout.py,tests/test_memory.py,tests/test_phase4.py,tests/test_phase3.py,tests/test_duck.py, andtests/test_eventsub_scopes.py. Tests stay offline:validateis stubbed and does not call Twitch.Needs owner
git log --all -- .envis empty. This supersedes the old V0-01 check.speaker_device: nullno longer refuses when a session backend is available. Confirm music dips for apps outsideduck_skipand that a mid-sentence exit restoresdata/duck.json.requirements.txton her PC and run pytest. The IPv6 host failure was starlette 1.6.0; the pin is 1.7.0.To show artifacts inline, enable in settings.