Repository navigation
Add app health metrics and log previously silent collab failures - #1467
Conversation
…ilures Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
5f9883d to
51ddfb0
Compare
Tim020
left a comment
There was a problem hiding this comment.
Review round 1
Head SHA: 51ddfb00faf2974a2bb4db11207aece2262690de
Verdict: Ready to merge after considering the two Important findings below (neither is a correctness bug in production today; both are design/coverage gaps worth a decision). No blocking issues.
Previous round follow-up: N/A — first round, no prior threads.
SonarQube: Quality Gate PASSED. All conditions pass (new reliability/security/maintainability ratings A, 0% duplication, 100% hotspots reviewed, 0 new lines needing coverage). 4 new issues reported, all MINOR/MAJOR code smells, none gate-blocking:
- 2 are in
server/utils/web/app_metrics.py(unnecessarylist()calls on WeakSets) — covered in inline comments below. - 2 are in
server/test/digi_server/test_logger.py(lines 94, 123 — preferassertLessEqual; usemonkeypatchinstead of manually restoringsys.excepthook). That file is not part of this PR's diff (gh pr diff 1467doesn't touch it) — Sonar is comparing against the eventualmainreference, so these pre-exist on the base branchfeature/obs-capture-stdlib-logs. Flagged here for awareness only; not actionable in this PR.
New findings: 3 Important, 6 Suggestions. No Critical issues.
Strengths:
- The stated goal (convert silent
except: passswallows to contextual logging) is executed thoroughly and correctly: the original exception still propagates everywhere it must (_write_checkpoint_sync'sraise), no new log line leaks a JWT, Yjs payload, or script content, and severity choices (WARNING forYJS_SYNC/YJS_UPDATE, DEBUG for the higher-frequencyYJS_AWARENESS) are deliberate and tested. - Metrics design is solid: label cardinality on
digiscript_ws_messages_totalis provably bounded (bounded_op+_KNOWN_OPS, backed bytest_known_ops_cover_every_handlerfor the dispatch-table half), the double-close guard (_counted_connection+_close_handled) is correct and well tested (double-close, close-without-open, reconnect all covered), and the gauges reading live state at scrape time avoid drift. - Test design shows real care:
_write_checkpoint_sync's cleanup test triggers a genuine EBADF rather than mocking it away, and the metrics tests correctly use before/after deltas (with an explicit comment acknowledging cross-test global-registry contamination) rather than asserting absolute values.
🤖 Generated with Claude Code
…rs, real OP coverage test Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Review round 1 follow-up, all in b2c8981:
Local: full pytest 1191 passed, ruff check and format clean. |
…tion order _live_session_value short-circuited once a live app had been seen, so a later failing app was never evaluated or logged. The WeakSet iteration order is address-dependent, which made test_one_failing_app_does_not_hide_a_live_session_elsewhere pass or fail with memory layout. Evaluate every app, and make the test check both orders explicitly. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Tim020
left a comment
There was a problem hiding this comment.
Review round 2
Head SHA: 01e64f4c73675da227278e1acb66a715212ee611
Verdict: Ready to merge. No blocking issues; one minor Suggestion below, genuinely optional.
Previous round follow-up (all in commit b2c8981):
- Verified fixed (8):
_live_session_valueno longer aborts on first failure (now checks every app, logs with type+id, NaN only when nothing confirmed);_count_roomsnow guards each manager individually (fixes the Important finding and the Sonarlist()smell in one change);get_sync("current_show")adopted; module docstring now distinguishes singleton metrics from per-instance weak-set registration;register_app_info()moved out ofws_controller.pyintoapp_metrics.pyitself; the_SESSION_OPS/_KNOWN_OPScomment reordered;logs_viewer's except block split intoStreamClosedError(DEBUG) vs. everything else (WARNING + traceback); the tautological_KNOWN_OPStest rewritten to parse the controller source viaastand catch any newelif ws_op == "X"branch. Each has an inline reply citing the exact fix and new/updated test, and all 8 threads are resolved. - Accepted with explanation, left open for you (1):
register_application()staying inRoomManager.__init__rather than moving toDigiScriptServer.__init__— the added comment's reasoning (scope + "every real app builds a RoomManager") is sound, so I replied accepting it, but left the thread unresolved since it's your call whether the explanation closes it. - Needs human decision: none.
SonarQube: Quality Gate PASSED. Fresh analysis confirmed against head SHA 01e64f4c... (analysed 2026-10-22T22:32:36Z). All conditions pass, and 0 new issues (down from 4 last round — both app_metrics.py smells fixed above; the two test_logger.py smells were never part of this PR's diff and aren't reported against this PR anymore). 0 security hotspots.
New findings: 1 Suggestion, anchored to code the round-1 fix introduced (not a missed round-1 item).
Strengths:
- The round-1 follow-up comment itemized every finding with what changed and where, which made this round's verification straightforward and accurate.
- Two of the fixes (the
_count_roomsguard, theast-based_KNOWN_OPStest) also added direct regression tests proving the fix works (test_failing_gauge_callbacks_do_not_break_the_scrapeliterally scrapesgenerate_latest()with an injected failure and asserts the other series survive), not just a code change taken on faith. test_one_failing_app_does_not_hide_a_live_session_elsewhereis a nice touch — it runs both WeakSet iteration orders viasubTestto make sure the fix isn't order-dependent.
🤖 Generated with Claude Code
…ination Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Round 2: the optional suggestion on |
…t RoomManager Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Round 3: |
|
Tim020
left a comment
There was a problem hiding this comment.
Review round 3
Head SHA: d106e36c82ebb7e54811f2a8f2947735018472da
Verdict: Ready to merge. No open findings, no new issues.
Previous round follow-up (2 threads, both now resolved):
- Verified fixed:
register_application()moved fromRoomManager.__init__to the end ofDigiScriptServer.__init__(app_server.py:347-352), exactly as suggested in round 1 — confirmed by two new tests (test_server_registers_itself_for_app_metrics,test_room_manager_registers_itself_but_not_the_application) that directly assert the split: aRoomManagerregisters itself but not its application. - Dispute resolved in the author's favour: my round-2 Suggestion about
_live_session_valuereturningNaNwhen a confirmedFalsefrom one app coexists with an unrelated app's failure. The counter-argument is correct — the gauge's contract is "confirm no live session anywhere," and aFalsefrom one app can't establish that while another app's state is genuinely unknown, soNaNis the right conservative answer, not a bug. The docstring now states the rule explicitly andtest_live_session_value_rule_pinnedpins all 6 cases (including both orderings of the mixed outcome) as a regression guard. Accepted and resolved.
SonarQube: Quality Gate PASSED. Fresh analysis confirmed against head SHA d106e36... (analysed 2026-10-22T23:01:31Z). All conditions pass, 0 new issues, 0 hotspots.
New findings: None. The incremental diff since round 2 (app_server.py, script_room_manager.py, app_metrics.py, plus the three test files) is exactly the two fixes above, each backed by a new, specific test — nothing else changed in the files this PR owns.
Strengths:
- Both fixes this round are minimal and surgical: the registration move touches only the two
__init__methods involved, and the docstring/test addition for_live_session_valuedoesn't change behaviour at all — it just makes an already-correct rule explicit and regression-proof. test_live_session_value_rule_pinnedis a good regression-test pattern: it enumerates the full truth table (confirmed-true, confirmed-false, failed, empty, and both orderings of mixed outcomes) in one table-driven test rather than scattering it across ad hoc cases.
🤖 Generated with Claude Code



Summary
server/utils/web/app_metrics.py:digiscript_ws_connections,digiscript_ws_messages_total{op}(bounded; unknown OPs reported asOTHER),digiscript_collab_rooms,digiscript_show_session_active,digiscript_info{version}.collab_roomsandshow_session_activeare read live at scrape time (RoomManager registers itself and its app), so they cannot drift on any close path.ws_connectionsis incremented inopen()and decremented exactly once inon_close()(guarded by_close_handledplus a per-handler counted flag).Testing
🤖 Generated with Claude Code