Module

contracts.rules_defer_falsy

Suspense{% if key %}defer-falsy footgun detection.

A deferred Suspense key isNonein the shell render, then resolves to real data. Templates that branch on raw truthiness ({% if key %}) treat empty list[], empty string "", 0 and Falseidentically to the loading state — the skeleton renders forever and a user sees a perpetual spinner with no console error.

CLAUDE.md and AGENTS.md document the fix ({% if key is not none %}or "key" in __chirp_defer_pending__); this rule promotes the docs to a startup-time contract check.

Detection is scoped to templates that self-declare their defer keys via "<NAME>" in __chirp_defer_pending__ or the <NAME> is deferredtest, so we don't false-positive on arbitrary{% if x %}elsewhere in the codebase. Severity isWARNING— the rule ships informational by default and can be promoted toERRORvia app.override_contract_severity("defer_falsy", Severity.ERROR)in CI.

Functions

_bare_truthy_pattern 1 re.Pattern[str]
Build a regex that matches ``{% if KEY %}`` / ``{% if not KEY %}``. Matches ki…
def _bare_truthy_pattern(key: str) -> re.Pattern[str]

Build a regex that matches{% if KEY %} / {% if not KEY %}.

Matches kidaif and elifstart tags with optional whitespace trimming ({%-, -%}) and an optional not. Crucially, the pattern requires the tag to end immediately after the identifier (\s*-?%}) — that's what excludes {% if KEY is none %}, {% if KEY == X %}, {% if KEY and Y %}, etc.

Parameters
Name Type Description
key str
Returns
re.Pattern[str]
check_defer_falsy_conditionals 1 list[ContractIssue]
Flag bare ``{% if KEY %}`` conditionals on Suspense-deferred keys. Only fires …
def check_defer_falsy_conditionals(template_sources: dict[str, str]) -> list[ContractIssue]

Flag bare{% if KEY %}conditionals on Suspense-deferred keys.

Only fires whenKEYis explicitly declared as a defer key in the same template (via__chirp_defer_pending__membership or the is deferred test). One WARNINGper (template, key) pair.

Parameters
Name Type Description
template_sources dict[str, str]
Returns
list[ContractIssue]