Contract checks for thesignal()primitive.
Dead-binding detection (chirp issue #238 — the dead-ticker class): a template
{{ signal('x') }} / sse-swap="x" bound to the merged /_chirp/live
connection with no registered@app.signal('x') / @app.derived('x')
producer is a silent dead binding — the element never updates.
Why this needs the explicit producer registry, not AST inference: signal names
are dynamic by nature (signal(name)), so the SSE crossref's literal-only
inference degrades to INFO and defeats the #238 goal. This rule validates
sse-swap listeners against snapshot.signal_names(the registry), which is
authoritative.
All signal bindings resolve to the single/_chirp/liveconnection, so this
rule scopes to templates that open ansse-connectpointing at the signal
stream (directly or viasignal_connect()), and validates every sse-swap
in that template against the registry.
contracts.rules_signals
| Name | Type | Default | Description |
|---|---|---|---|
type
|
|
— | |
qualified_name
|
|
— | |
element_type
|
|
— | |
description
|
|
— | |
source_file
|
|
— | |
line_number
|
|
— | |
is_autodoc
|
|
— | |
autodoc_element
|
|
— | |
_autodoc_template
|
|
— | |
_autodoc_url_path
|
|
— | |
_autodoc_page_type
|
|
— | |
title
|
|
— | |
doc_content_hash
|
|
— |
Symbols on this page
Signal names bound viasignal() / signal_block() / signal_bind()calls.
Count/_chirp/liveconnect sites in source.
Whether source opens ansse-connect pointing at /_chirp/live.
Matches both a literalsse-connect="/_chirp/live..."and the
signal_connect()global call (which emits that connect at…
Whether source opens ansse-connectto a non-signal stream.
Hand-writtensse-swap values, excluding signal*()helper bindings.
Hand-written htmx 4 signal markers outside the template helpers.
Cross-check signalsse-swapbindings against registered producers.
- Dead binding (ERROR, #238): an
sse-swap="x"under the signal stream with no registeredsignal('x')producer. - Orphan producer…
Error when session-scoped signals exist withoutSessionMiddleware.
Session-scoped signals resolve their audience key from the session; without
SessionMiddlewarethe key is never available…
Warn when a derived signal depends on both global and session signals.
INFO when more than one persistent/_chirp/livescope is opened.
Browsers cap concurrent SSE connections per origin (HTTP/1.1 footgun). One
signal_connect()wrapper per composed…
_signal_call_names
function
def _signal_call_names(source: str) -> set[str]
Signal names bound viasignal() / signal_block() / signal_bind()calls.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
source
|
str
|
— |
_count_signal_stream_connects
function
def _count_signal_stream_connects(source: str) -> int
Count/_chirp/liveconnect sites in source.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
source
|
str
|
— |
_connects_to_signal_stream
function
def _connects_to_signal_stream(source: str) -> bool
Whether source opens ansse-connect pointing at /_chirp/live.
Matches both a literalsse-connect="/_chirp/live..."and the
signal_connect()global call (which emits that connect at render time and
appears as a normalized__p__expression here).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
source
|
str
|
— |
_has_competing_sse_connect
function
def _has_competing_sse_connect(source: str) -> bool
Whether source opens ansse-connectto a non-signal stream.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
source
|
str
|
— |
_raw_sse_swap_names
function
def _raw_sse_swap_names(source: str) -> set[str]
Hand-writtensse-swap values, excluding signal*()helper bindings.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
source
|
str
|
— |
_raw_signal_marker_names
function
def _raw_signal_marker_names(source: str) -> set[str]
Hand-written htmx 4 signal markers outside the template helpers.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
source
|
str
|
— |
check_signal_bindings
function
def check_signal_bindings(template_sources: dict[str, str], signal_names: frozenset[str]) -> list[ContractIssue]
Cross-check signalsse-swapbindings against registered producers.
- Dead binding (ERROR, #238): an
sse-swap="x"under the signal stream with no registeredsignal('x')producer. - Orphan producer (INFO): a registered signal no binding listens for.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
template_sources
|
dict[str, str]
|
— | |
signal_names
|
frozenset[str]
|
— |
check_signal_scope
function
def check_signal_scope(middleware_list: list[Any], session_signal_names: frozenset[str]) -> list[ContractIssue]
Error when session-scoped signals exist withoutSessionMiddleware.
Session-scoped signals resolve their audience key from the session; without
SessionMiddlewarethe key is never available and per-visitor fan-out is
silently broken.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
middleware_list
|
list[Any]
|
— | |
session_signal_names
|
frozenset[str]
|
— |
check_signal_mixed_audience_derived
function
def check_signal_mixed_audience_derived(mixed_audience_derived_names: frozenset[str]) -> list[ContractIssue]
Warn when a derived signal depends on both global and session signals.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
mixed_audience_derived_names
|
frozenset[str]
|
— |
check_signal_connect_budget
function
def check_signal_connect_budget(template_sources: dict[str, str]) -> list[ContractIssue]
INFO when more than one persistent/_chirp/livescope is opened.
Browsers cap concurrent SSE connections per origin (HTTP/1.1 footgun). One
signal_connect()wrapper per composed page is the supported pattern.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
template_sources
|
dict[str, str]
|
— |
View source · /home/runner/work/chirp/chirp/site/../src/chirp/contracts/rules_signals.py:1