Changed
- CodeQL workflow now cancels superseded analyses on rapid PR pushes (#1340). Added
concurrency: { group: ${{ github.workflow }}-${{ github.ref }}, cancel-in-progress: true }to.github/workflows/codeql.yml. The latest commit's analysis is what matters; older runs are obsolete and only add noise to the PR check list. Investigation in #1340 surfaced that the v0.9.3 drain's "stale CodeQL check-run" framing was a misdiagnosis — most "stale CodeQL fail" check-runs were real GitHub Advanced Security alerts, not stale leftovers. The--adminmerge requirement comes from the 1-approving-review rule (solo maintainer can't self-approve), not from CodeQL. This concurrency block reduces the run-list noise that fueled the misdiagnosis without changing merge behavior. Triage of the 8 real open CodeQL alerts (1 high-severity) tracked in #1343.
Fixed
_mount_onenow returns a consistent 5-tuple from every path (#1343). Theexcept Exceptionbranch inLiveViewConsumer._mount_one(websocket.py:2469) returned a 4-tuple while every other path returned a 5-tuple(ok, payload, err, nav, push_events). The single caller inhandle_mount_batchunpacks 5 values; the mismatch raisedValueError: not enough values to unpack, masking the per-view error in the batchfailed[]plumbing. Surfaced by CodeQLpy/mixed-tuple-returnsalert. Returns[]forpush_eventsfrom the exception path. 1 regression test intest_sw_advanced.py::TestMountBatch::test_mount_one_returns_5_tuple_on_unhandled_exception.deploy_cli.pyno longer has a bareexcept: passfor transient status-poll errors (#1343). Surfaced by CodeQLpy/empty-exceptalert. Replaced withlogger.debug("status poll failed; retrying", exc_info=True)- an explanatory comment. CLAUDE.md security rule #5 forbids bare
except: passframework-wide.
- an explanatory comment. CLAUDE.md security rule #5 forbids bare
python/djust/tests/now included inmake test-python+check-test-coveragetarget (#1339). The Makefile's test targets used explicit pytest paths (tests/ python/tests/) which override pyproject.toml's testpaths, silently excludingpython/djust/tests/(2,734 tests across 100+ files). Added the missing directory to test-python, test-python-parallel, and the background test target. Newmake check-test-coveragetarget prevents recurrence by verifying every test directory is collected by CI. Verified bymake check-test-coverageand the 2,734 newly-collected existing tests.@reactive now fails at class-definition time on classes missing
update()(#1287). The@reactivedecorator previously guardedself.update()withhasattr(self, 'update'), silently no-opping when the host class lacked the method. It now uses__set_name__to validate at class-definition time, raisingTypeErrorwith a clear message. The_ReactivePropertydescriptor also callsupdate()automatically for both default and custom setters. 6 regression cases intest_decorator_reactive_requires_update.py.@background docstring now documents return-value contract (#1288). The decorator's docstring mentions that handler return values are discarded and points users to
@action+_action_statefor result tracking. 2 regression cases intest_background_return_value_docs.py.@computed memoized cache is now thread-safe (#1289). The
@computeddecorator's memoized form previously mutated the per-instance cache dict without synchronization, creating a race window between threads (e.g. a@backgroundcallback and template rendering). A per-instancethreading.Locknow protects the check-then-act cache mutation. 3 regression cases intest_decorator_computed_thread_safety.py.New
make check-handler-contractslinter (#1290).scripts/check-handler-contracts.pycross-references template-tag_eventemit defaults against component/mixin handler method names, catching #1275-class (stale/typo'd emit default) bugs at pre-push time. 44 emit defaults (26 framework, 18 app-level) validated clean. Added to pre-push hook. 7 test cases intest_check_handler_contracts.py.dj-form-pending now visible on WebSocket path (#1315).
sendEvent()was fire-and-forget — it returnedtruesynchronously, causinghandleEvent()to resolve immediately on the WebSocket path._setFormPending(false)fired before any browser repaint, so the pending state (spinner, disabled inputs, hidden labels) was never visible.sendEvent()now returns aPromisethat resolves when the server's response (patch/noop/error with matching ref) arrives, via a new_pendingEventResolversMap alongside the existing pending-event tracking. All clear sites resolve pending resolvers on disconnect. 2 regression cases indj-form-pending.test.js(WebSocket path block).@server_function no longer hard-codes auth check (#1316).
dispatch_server_functionpreviously had an inline anonymous-user check that rejected all unauthenticated callers regardless of the view'slogin_requiredsetting. The check is removed —check_view_auth(view-levellogin_required/permission_required) andcheck_handler_permission(handler-level@permission_required) now govern auth, matching the ADR-008 contract.@server_functionno longer requires authentication by default. 4 regression cases intest_server_functions.py.#1281 regression tests moved to
python/tests/for CI coverage (#1325).test_skip_render_private_state.py(9 tests) was inpython/djust/tests/which is excluded from the explicit paths inmake test-pythonand the CI workflow. Moved topython/tests/so CI collects the tests on every run.