Kida 0.7.0

strict-by-default release — strict_undefined flips to True, parser error hints for Jinja2 traps, jinja2_compat_warnings on by default, and render-surface hardening

Released 2026-04-20.

Kida 0.7.0 finishes the "strict by default" transition announced in 0.6.0.strict_undefined=True is now the default, parser errors for Jinja2-only keywords include targeted migration hints, and the {% set %} scoping trap now emits a MigrationWarningout of the box. Also: RenderCapture for block-level capture and search indexing, render-surface parity corpus, and leaf-node hardening.

Breaking

  • strict_undefined=True is the default — Missing variables and missing attribute access now raise UndefinedError with a descriptive message distinguishing variable / attribute / key lookups. Previously missing attributes silently rendered as "", contradicting the documented stance. Escape hatch: pass strict_undefined=False on the Environmentto restore the prior lenient behavior as a transitional shim. (#107)

Added

  • Parser error hints for Jinja2 trapsK-PAR-001 now prepends a targeted migration suggestion before the generic keyword list. Covers macro{% def %}, endmacro / endset → unified {% end %}, namespace{% let %} / {% export %}, and fill / endfill{% slot %} inside {% call %}. The trap table in kida.parser.errors.JINJA2_TRAPSis data-only — trivial to extend. (#106)
  • RenderCapture — Block-level capture, search indexing, and freeze cache. (#99)
  • Reject non-top-level{% def %} / {% region %} — Definitions nested inside other blocks fail fast at parse time with a retargeted Undefined hint. (#100)
  • Python 3.14+ idiomsTypedDict, match/case, and __slots__adopted across the codebase. (#98)
  • Render-surface parity corpus & sandbox fuzz — HTML / terminal / markdown parity corpus, fragment scaffolding, and sandbox fuzz harness. (#103)
  • AGENTS.md — Contributor safety/values guide for agents working in this repo. (#104)

Fixed

  • Docs:{% macro %} false claim corrected across CLAUDE.md, migration docs, and release notes. {% macro %} is not a valid Kida keyword — rename to {% def %}. (#106)
  • CoercionWarningcoverage — Now extends to collection / number filters; lint gates added. (#97)
  • PrecedenceWarning— parenthesized nullish fallback — Warning no longer fires when the nullish fallback is explicitly parenthesized. (#96)
  • GitHub Action default Python version — Bumped from 3.12 to 3.14 to match project support. (#94)
  • Leaf-node hardening — Bug fixes, dead-code removal, test-gap closure across parser / compiler leaf nodes. (#105)

Changed

  • jinja2_compat_warnings defaults to TrueMigrationWarning (K-WARN-002) fires out of the box on the canonical {% set %} scoping trap (nested {% set x %} shadowing an outer {% let x %} or {% export x %}). The trigger is narrowly scoped — fresh names used for legitimate block-scoped work do not warn. Suppress via Environment(jinja2_compat_warnings=False) or warnings.filterwarnings("ignore", category=MigrationWarning). (#106)

Upgrade Notes

  1. Audit templates for implicitNone / missing attribute access. Anywhere you relied on {{ user.nickname }} silently rendering "" when nicknameis missing, switch to one of:
    • {% if user.nickname is defined and user.nickname %}{{ user.nickname }}{% end %}
    • {{ user.nickname ?? "" }}
    • {{ user.nickname | default("") }}
  2. Temporary escape hatch:Environment(strict_undefined=False)restores prior lenient behavior. Plan to remove this before the next release.
  3. Expect newMigrationWarning output if your templates hit the {% set %} scoping trap. Fix the trap (usually: switch to {% let %} or {% export %}) or filter the warning.
  4. GitHub Action version tag updated to@v0.7.0.