fix: resolve the five review-pass nits (#269) - #299
Merged
Conversation
general.py reused "audit.settings_updated" — the audit router's action — so a SIEM rule or ?action= filter could not tell "someone rewired audit forwarding" from "someone changed rate limits". Now "general.settings_updated". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
reset_provider_cache dropped the adapter without closing its SDK client, and it fires on every LLM- and proxy-settings save — each reset leaked the client's httpx pool (FDs/sockets) in a process meant to run indefinitely. Both adapters gain aclose(); the reset stays sync and spawns the close onto the running loop, discarding the coroutine when there is none to leak into. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
POST /report/summary spawned run_summary_pipeline with no in-flight guard, so a double-click bought two provider calls racing into ExecutiveSummary's exercise_id unique constraint, the loser dying as a logged pipeline failure. queue_summary_pipeline mirrors queue_llm_pipeline's guard, and generate_executive_summary gains the assess-path IntegrityError recovery: roll back (discarding the buffered WS event), return the winner's row. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…es (#269) create_sample_demo_exercise released the start node's physical inject chosen by unordered .first(); on a multi-team start node that can be another team's copy, whose audience is empty (only the demo member's group is enrolled), and release_inject 409s the whole demo load. It also activated without schedule_exercise_injects, so a sample's release_at_minutes timers never armed until a restart or pause/resume. Latent with the bundled single-team-start samples; a trap for the next sample added. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
When the exercise API 403s (non-member) or 404s, participantView.init() left exercise=null with loading=false — both the spinner and the content hid, giving a fully blank page while a WS connect was still attempted. Authz is unchanged (the page is shell-only; the API scopes data): init now records a load error, renders a visible dead end with a route back to the dashboard, and skips the clock and WS entirely. Covered by a Playwright regression in the CI ui job. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.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.
Resolves all five verified defects from the July review pass, one commit each.
general.pyemittedaudit.settings_updated, the audit router's own action, so SIEM rules couldn't tell "audit forwarding rewired" from "rate limits changed". Nowgeneral.settings_updated.reset_provider_cache(fired on every LLM- and proxy-settings save) dropped the adapter without closing its SDK client. Both adapters gainaclose(); the sync reset spawns the close onto the running loop and discards the coroutine when no loop exists.POST /report/summarynow dedupes viaqueue_summary_pipeline(same shape asqueue_llm_pipeline's guard; second click returnsalready-running), andgenerate_executive_summarygains the assess-pathIntegrityErrorrecovery: the race loser rolls back — discarding its buffered WS event — and returns the winner's row instead of dying as a logged pipeline failure..first(), which on a multi-team start node could grab another team's copy and 409 the whole demo load on an empty audience; activation now armsrelease_at_minutestimers viaschedule_exercise_injects(none of the bundled samples define one, so this is future-proofing, not a behaviour change for them).Verification: 745 passed / 2 skipped locally (the Playwright suite runs in CI's
uijob, including a new non-member regression test), ruff, pyright 0 errors, djlint clean, biome clean on the changed JS. New regression tests: provider-cache close, summary race + endpoint dedupe, multi-team demo seeding, non-member participate page.Closes #269
🤖 Generated with Claude Code