System
· little-sister {{ version }}
{# Server-seeded, same contract as the dashboard's stamp (ADR-0005):
this page doesn't navigate on its own, so it always says from when
the information below actually is. Under the kiosk layout the slim
line already carries it — there must be exactly one #status-updated
on the page, because that is what the poller looks for. #}
{% if layout != 'kiosk' %}
updated {{ rendered_at }}
{% endif %}
{% include '_system_info.html' %}
{# The registered check types and who answers for each. A type may come from
a separately released package (ADR-0051), so this is the only place an
operator can read which code — and which version — is behind a `type:`
name in their YAML. Always shown: there are always the built-ins, and the
point is the comparison between them and everything else.
Split, though. The types this configuration runs come first; the rest
fold into a disclosure, because on a small deployment they are most of
the card and none of the question being asked. They stay reachable
because a registered-but-unused type is the proof a freshly installed
plugin took — see `_type_roster`, which owns the reasoning. #}
{#- Top-aligned, alone among this page's tables, because alone among them
a row here can grow: opening "used by 9 checks" stretches the Type cell
down a list of node paths, and centering put Module, Version and From
halfway down that list, beside nothing they describe. They answer for
the type named at the top of the row, so that is where they sit. -#}
{%- macro type_table(rows) %}
| Type | Module | Version | From |
{% for row in rows %}
{%- set origin = row.origin %}
{#- "used by", because a bare count under a type name
reads as something the *package* brought — two
checks shipped — when it is the opposite: how many
checks in this deployment's configuration name this
type. A package contributing one type to two checks
is the ordinary case, so the ambiguous phrasing was
wrong most of the time.
And the count opens. It is the right summary at a
glance, but it was the one number on this page that
the page could not substantiate — *two of what?* —
while every other card here names its subjects. A
disclosure rather than a tooltip: the list is as
long as the deployment is large, and it has to
survive a keyboard and a screenshot. The unused
types below have no list, and say so by not
offering one. -#}
{{ origin.type_name }}
{%- if row.count %}
used by {{ row.count }} check{{ 's' if row.count != 1 else '' }}
{#- The node path, not the check's name: the
path is the thing the reader can go and
look at, so each is a link to that node. -#}
{%- for path in row.paths %}
- {{ path }}
{%- endfor %}
{%- endif %} |
{#- The loaded path under the module name, because the
version beside it is the installed metadata's claim:
a source copy earlier on the path shadows an
installed distribution of the same name, and then
the version is answering for code that is not
running. Exactly the case somebody reads this table
to diagnose, so the table shows both.
Against a root the reader has, not absolutely: the
diagnostic is *which root*, and nine tenths of an
absolute path is the same prefix on every row —
starting with somebody's home directory. The whole
string stays one hover away. -#}
{{ origin.module }}
{% if origin.path %} {{ origin.path | loaded_from }}{% endif %} |
{% if origin.version %}{{ origin.version }}{% else %}—{% endif %} |
{% if origin.builtin %}built-in{% elif origin.distribution %}{{ origin.distribution }}{% else %}source{% endif %} |
{% endfor %}
{%- endmacro %}
Check types
{% if types_in_use %}
{{ type_table(types_in_use) }}
{% if types_folded %}
{#- The count belongs in the summary: a closed disclosure has to say
what it is hiding, or an operator looking for a type they cannot
find has no reason to open it. #}
{{ types_folded | length }} more registered type{{ 's' if types_folded | length != 1 else '' }}, unused by this configuration
{{ type_table(types_folded) }}
{% endif %}
{% else %}
{#- Nothing to split against (no engine, or no checks) — and that is
the moment the roster matters most, so it is shown whole. #}
{{ type_table(types_folded) }}
{% endif %}
{# What is installed beside the library. A package reaches this instance
through four seams and the tables below are each about one of them, so
until this card the *version* of a package that registers no check type
was unreadable from the running instance — see `_registering_packages`.
One row per installation, not per contribution: the loaded path and the
release belong to the package, and printing them on every slot row would
say the same thing twice for a package that fills two. Absent when
nothing but the library registered anything. #}
{% if packages %}
Packages
{#- Two columns, not three. A column of its own left the loaded
path a narrow ribbon breaking at the hyphen in
"site-packages" while squeezing everything either side of
it; under the name it has the table's whole width and needs
none of it, now that the path is drawn against a root
(`loaded_from`) instead of absolutely. The column stays a
column because what it holds is one thing — this package's
identity: what it is called, what was installed, and where
that turned out to be. -#}
| Package | Registers |
{% for row in packages %}
{#- The import name is what every other table on this
page prints, so it leads; the distribution and
version sit beside it because that pair is what an
operator compares against what they installed. A
package with no installed metadata is a copy on the
path — the shadowing case, worth saying out loud. -#}
{{ row.origin.package }}
{% if row.origin.distribution %}· {{ row.origin.distribution }} {{ row.origin.version }}{% else %}· source{% endif %}
{%- if row.origin.path %} {{ row.origin.path | loaded_from }}{% endif %} |
{#- Each registration is one fact and must not break
across lines: "slot reason.actions" split after
"slot" reads as two entries, and the column is
narrow enough for that to happen. The list still
wraps *between* items — that is what the breaks
are for. -#}
{%- for item in row.registers %}
{{ item }}{% if not loop.last %} {% endif %}
{%- endfor %} |
{% endfor %}
{% endif %}
{# The extension seams (ADR-0034 / ADR-0035 / ADR-0064), outside #system-info
because they are decided at import time and never move while the process
runs — re-fetching them on the ~10s poll would say nothing new.
Registration is import-order sensitive and each of its failures is a log
warning, so the running instance has to be able to answer "did my
extension take?" without anyone opening a log file.
`slot_fillers` is `all_fillers()` and the library registers its own two
unconditionally, so in practice this card is always drawn and the guard is
what makes that a *fact about the fillers* rather than an assumption here.
The resolver list below is deliberately not part of it: it would make the
guard unreachable, and an unreachable condition is one no test can hold. #}
{% if slot_fillers or extra_aspects %}
Extensions
{% if slot_fillers %}
| Slot | Package | Template | Context | From |
{% for filler in slot_fillers %}
{{ filler.slot }} |
{{ filler.package }} |
{{ filler.template }} |
{% if filler.context %}provider{% else %}—{% endif %} |
{#- Which kind: a dependent package's registration, or
the library's own declarative action list, which
fills the same slots through the same seam
(ADR-0038). Worth naming, because an operator
looking here after adding a config action needs to
see the difference between "mine" and "theirs". -#}
{% if filler.builtin %}built-in{% else %}extension{% endif %} |
{% endfor %}
{% endif %}
{% if resolvers %}
{#- Every claimed secret scheme with the package that answers for it
(ADR-0064), drawn as the slot table above is and not as a prose
line: a deployment with a few named identities has seven or more
of these, and a comma list of `scheme (package)` pairs wrapped
into a paragraph where the eye has to re-find the boundary on
every item. Two seams, one shape — the columns even mean the same
things, `From` telling the library's own claim from a package's
exactly as it does for a filler.
The built-in `env` is listed too, unlike the aspects line below:
the schemes are additive and a reference names exactly one, so
this table is what a config field may say — and leaving the
library's own claim out would make an *override* of it look like
an ordinary registration. `Replaces` is empty in every ordinary
deployment and stays a column anyway, because a replacement is
the one fact on this seam that the outcome cannot show. #}
| Scheme | Package | Replaces | From |
{% for row in resolvers %}
{{ row.scheme }}:// |
{{ row.owner }} |
{% if row.replaced %}{{ row.replaced }}{% else %}—{% endif %} |
{% if row.builtin %}built-in{% else %}extension{% endif %} |
{% endfor %}
{% endif %}
{% if extra_aspects %}
{#- Each name with the package that registered it: the name alone
says the file is *declared*, which is not the question when the
file is misbehaving. An owner is absent only where the caller
could not be inferred, and then nothing is claimed. Still a line
rather than a table: an aspect has one fact beyond its owner and
a deployment has one or two of them, which is a sentence. #}
Registered configuration aspects:
{% for name, owner in extra_aspects %}config/{{ name }}{% if owner %} ({{ owner }}){% endif %}{% if not loop.last %}, {% endif %}{% endfor %}
{% endif %}
{% endif %}
{# The effective Content-Security-Policy (ADR-0048 §7). Always shown, unlike
the extensions card above: there is always a policy, and the reason to
print it is that a source may come from a *package* — a request blocked
inside somebody else's code is undebuggable from here unless the page says
who asked for each origin. The header name is part of the answer: a
Report-Only policy reports and blocks nothing. #}
Content-Security-Policy
{{ csp_header }}
| Directive | Sources |
{% for directive, sources in csp_directives %}
{{ directive }} |
{%- for source in sources %}
{{ source.value }}
({{ source.by }})
{%- if not loop.last %} {% endif %}
{%- endfor %}
|
{% endfor %}
{% include '_page_end.html' %}