Module

contracts.rules_composition

Page-template-extends-registered-layout footgun detection.

When a page-leaf template uses{% extends "_layout.html" %}and _layout.htmlis registered as a layout in this page's chain, two things break silently:

  1. Block overrides are dropped.render_with_blocksonly injects the page's rendered HTML into the layout'scontentslot — sibling block overrides like{% block page_scripts %}defined on the page never reach the layout. The page author wonders why their inline script tag doesn't show up; nothing in the console explains it.

  2. The layout structure renders twice. kida's extends inheritance fills the layout structure during page render, thenrender_with_layouts wraps that already-wrapped HTML in the same layout chain again — the <html>/<body>shell appears nested inside itself.

check_unreachable_blockscovers the no-extends sibling-block case but explicitly skips templates that use{% extends %}(see rules_unreachable_blocks.py); this rule is the complementary check targeting the extends-into-a-registered-layout case.

Detection is conservative: only fires when the extended target is in this app's set of registered layout template names. Pages that extend a non-layout kida partial (e.g. the_page_layout.htmlpattern in examples/standalone/oob_layout_chain/) are intentionally allowed.

Functions

_registered_layout_names 1 set[str]
Collect every layout template name registered in any page chain.
def _registered_layout_names(layout_chains: list[Any]) -> set[str]
Parameters
Name Type Description
layout_chains list[Any]
Returns
set[str]
check_page_extends_layout 3 list[ContractIssue]
Flag page-leaf templates that ``{% extends %}`` a registered layout. Compositi…
def check_page_extends_layout(page_leaf_templates: set[str], layout_chains: list[Any], kida_env: Environment | None) -> list[ContractIssue]

Flag page-leaf templates that{% extends %}a registered layout.

Composition (render_with_blocks) and inheritance ({% extends %}) are not interchangeable in Chirp's page convention. When both are in play against the same template, block overrides drop silently and the layout structure renders twice.

Parameters
Name Type Description
page_leaf_templates set[str]
layout_chains list[Any]
kida_env Environment | None
Returns
list[ContractIssue]