Fixed
- Inheritance resolution doubled filter-arg quotes —
|date:"M d, Y"rendered as"Apr 25, 2026"(closes #1081) —nodes_to_template_stringincrates/djust_templates/src/inheritance.rswas wrapping every filter arg in\"…\"when serializing the resolved-inheritance AST back to a template string. Butparse_filter_specsdeliberately preserves any surrounding quotes on literal args (the dep-tracking extractor needs them to disambiguate literals from bare-identifier variable references — see #787). So an arg parsed from|date:"M d, Y"came out of the parser as the string"M d, Y"(with the quote chars), and the round-trip wrapped it again to produce|date:""M d, Y"". Re-parsing the resolved template then stripped the outer pair, leaving the inner"M d, Y"as the format spec; chrono treats"as literal output characters in strftime-style formats, so the rendered date came out as"Apr 25, 2026", then HTML-escape converted the"to"— surfacing as"Apr 25, 2026"in the rendered DOM. The fix emits the arg verbatim (|filter:{arg}) sinceparse_filter_specsalready preserves the source-form quotes; round-trip is now idempotent. Same fix applied to theNode::InlineIfbranch (a{{ x if cond else y | filter:"…" }}chain has the same shape). 29 regression cases intests/unit/test_filter_literal_args_1081.py+ 3 incrates/djust_templates/src/inheritance.rslock the round-trip invariant. Surfaced via PR #1086 against an actual 26,785-char inheritance-resolved template (<style>blocks with quoted CSS font names + the date filter). Failure mode was inheritance-resolution-specific: simple inline templates (no{% extends %}) never hitnodes_to_template_stringand rendered correctly all along — which is why the simple-template regression suite passed but production templates with inheritance failed.
Added
- Regression tests locking literal filter-arg quote stripping (#1081) — issue reported
{{ d|date:"M d, Y" }}rendering as"Apr 25, 2026"(literal double-quotes wrapping the result) and{{ x|default:"fallback" }}rendering as"fallback". Investigation across all renderer code paths confirmed the existingstrip_filter_arg_quoteshelper (landed v0.5.2rc1 via #787) is invoked at every filter-application site:render_node_with_loader(Variable + InlineIf nodes, both call sites atcrates/djust_templates/src/renderer.rs:271,328) andget_valuefor inline filter chains (renderer.rs:1556 — inlinearg_str = arg_str[1..len-1]strip). When the issue was reopened with a more specific reproduction path ("DjangoDateFieldfrom a model passes through the Rust context serializer before being filtered, output is inserted as JSON string value into VDOM"), re-tested the named path and confirmedserialize_context(crates/djust_live/src/lib.rs:1776-1781) returns the bare ISO string —value.call_method0("isoformat")is passed straight throughinto_pyobjectwith noserde_json::to_stringor quote-wrapping. No reproducible code path produces the reported output onmain(= v0.8.3rc1). Newtests/unit/test_filter_literal_args_1081.pyships 24 cases covering every literal-arg shape from the issue body, follow-up comments, and reopen: (1)|datewith"M d, Y"/"F j, Y"/ single-quoted format / dotted-path field access; (2)|defaultwith simple word / multi-word / slash / em-dash / dash / "No" / single-quoted / truthy passthrough / None fallback; (3) chains (|date:"…"|default:"…",|default:"…"|upper); (4) HTML attribute context (where any leftover literal quote would surface as"); (5)serialize_contextoutput shape — bare ISO string fordate/datetime/ list-of-dicts (the queryset+model+date path named in the reopen); (6) fullLiveView.render()with Django Model + DateField via the JIT serializer; (7)LiveView.render()with list of Model instances (_jit_serialize_queryset/_jit_serialize_modelpath); (8)render_with_difffull + partial (the WS-update path the reopen described as inserting JSON-quoted values into the VDOM). Locks the invariant against future renderer / VDOM-patch / JIT-serializer / context-serializer refactors so the JSON-quoting class of bug cannot silently re-emerge.
Changed
ROADMAP.mdstaleness sweep (post-v0.8.3rc1) — verified each unchecked Priority Matrix row, Quick Wins bullet, Medium Effort bullet, Major Features bullet, and Phoenix LiveView Parity Tracker row against the codebase. Marked ~30 items with ✅ + strikethrough + the actual implementation path (e.g.static/djust/src/26-js-commands.jsfor JS Commands,python/djust/streaming.pyfor AI streaming primitives,crates/djust_vdom/src/parser.rsfor keyed for-loop change tracking). Annotated the genuinely-pending items with*(verified: no … references in tree)*so the next person to triage doesn't re-discover the same false signals. Items confirmed shipped: JS Commands, Flash messages,on_mounthooks, Function components,assign_async/AsyncResult, Template fragments, Keyed for-loop change tracking, Temporary assigns,dj_suspense, Named slots with attributes, Server Actions (@action), Async Streams, Keep-Alive/dj-activity, WebSocket compression,dj-track-static,dj-no-submit,page_loadingon push,dj-sticky-scroll,dj-paste,dj-ignore-attrs,handle_params,handle_async, Hot View Replacement,dj-lock,dj-auto-recover,dj-cloak,dj-copy, Scoped JS selectors, Componentupdatecallback, Nested components (LiveComponent), Targeted events (dj-target), Declarative assigns, Selective re-rendering (VDOM partial),handle_info, Animations (dj-transition), Transition groups (dj-transition-group), Exit animations (dj-remove), DOM mutation events (dj-mutation), Sticky scroll, CSP nonce, Viewport events, Direct-to-S3 uploads, Prefetch on hover/intent (dj-prefetch), Server functions (@server_function), Push navigate, Back/forward restoration, Paste event handling, Scroll into view, AI streaming primitives. Items confirmed genuinely-pending (with greppable evidence): View Transitions API,used_input?,@restattribute spread,self.defer(callback), Multi-tab sync (BroadcastChannel), Offline mutation queue, State undo/redo, Connection multiplexing, Portal rendering, Server-only components, Islands of interactivity, i18n live language switching. Docs-only change; no runtime behavior.