djust 0.9.3rc2

Pre-releaseReleased

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 --admin merge 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_one now returns a consistent 5-tuple from every path (#1343). The except Exception branch in LiveViewConsumer._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 in handle_mount_batch unpacks 5 values; the mismatch raised ValueError: not enough values to unpack, masking the per-view error in the batch failed[] plumbing. Surfaced by CodeQL py/mixed-tuple-returns alert. Returns [] for push_events from the exception path. 1 regression test in test_sw_advanced.py::TestMountBatch::test_mount_one_returns_5_tuple_on_unhandled_exception.

  • deploy_cli.py no longer has a bare except: pass for transient status-poll errors (#1343). Surfaced by CodeQL py/empty-except alert. Replaced with logger.debug("status poll failed; retrying", exc_info=True)

    • an explanatory comment. CLAUDE.md security rule #5 forbids bare except: pass framework-wide.
  • python/djust/tests/ now included in make test-python + check-test-coverage target (#1339). The Makefile's test targets used explicit pytest paths (tests/ python/tests/) which override pyproject.toml's testpaths, silently excluding python/djust/tests/ (2,734 tests across 100+ files). Added the missing directory to test-python, test-python-parallel, and the background test target. New make check-test-coverage target prevents recurrence by verifying every test directory is collected by CI. Verified by make check-test-coverage and the 2,734 newly-collected existing tests.

  • @reactive now fails at class-definition time on classes missing update() (#1287). The @reactive decorator previously guarded self.update() with hasattr(self, 'update'), silently no-opping when the host class lacked the method. It now uses __set_name__ to validate at class-definition time, raising TypeError with a clear message. The _ReactiveProperty descriptor also calls update() automatically for both default and custom setters. 6 regression cases in test_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_state for result tracking. 2 regression cases in test_background_return_value_docs.py.

  • @computed memoized cache is now thread-safe (#1289). The @computed decorator's memoized form previously mutated the per-instance cache dict without synchronization, creating a race window between threads (e.g. a @background callback and template rendering). A per-instance threading.Lock now protects the check-then-act cache mutation. 3 regression cases in test_decorator_computed_thread_safety.py.

  • New make check-handler-contracts linter (#1290). scripts/check-handler-contracts.py cross-references template-tag _event emit 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 in test_check_handler_contracts.py.

  • dj-form-pending now visible on WebSocket path (#1315). sendEvent() was fire-and-forget — it returned true synchronously, causing handleEvent() 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 a Promise that resolves when the server's response (patch/noop/error with matching ref) arrives, via a new _pendingEventResolvers Map alongside the existing pending-event tracking. All clear sites resolve pending resolvers on disconnect. 2 regression cases in dj-form-pending.test.js (WebSocket path block).

  • @server_function no longer hard-codes auth check (#1316). dispatch_server_function previously had an inline anonymous-user check that rejected all unauthenticated callers regardless of the view's login_required setting. The check is removed — check_view_auth (view-level login_required / permission_required) and check_handler_permission (handler-level @permission_required) now govern auth, matching the ADR-008 contract. @server_function no longer requires authentication by default. 4 regression cases in test_server_functions.py.

  • #1281 regression tests moved to python/tests/ for CI coverage (#1325). test_skip_render_private_state.py (9 tests) was in python/djust/tests/ which is excluded from the explicit paths in make test-python and the CI workflow. Moved to python/tests/ so CI collects the tests on every run.

All releases · Atom feed