{% from '_maintenance_fields.html' import maintenance_fields with context %} {% from '_status_cue.html' import status_cue %} {% from '_record_list.html' import record_list %} {# the node, not the section: three leaf tabs open at once should be tellable apart #} {% set page_title = node.name %} {% include '_header.html' %}
{# The same band as the dashboard — a deep breadcrumb and an ellipsed title — minus the parts a detail page has no business showing: it is not polled, so it carries no freshness stamp, and it has nothing to filter. #} {% include '_page_band.html' %} {% include '_said.html' %}

{{ node.name }}

{% if node.description %}

{{ node.description | markdown_inline }}

{% endif %} {% if node.about %}
About: {{ node.about | markdown }}
{% endif %}
{#- The `node.actions` slot (ADR-0034, second slot): the same action as the card head's, on the page where the node is the subject. It sits with the status rather than with the reason lines, because that is precisely the distinction it exists for — this control is about the node, the per-line ones are about one finding (ADR-0036). -#} {{ slot('node.actions', node=node, surface='check') }} {#- "maintenance · error" rather than a bare "maintenance": naming what is being silenced is the transform being made visible (ADR-0032 rule 5), and before the keystone the reading it names was not merely hidden but overwritten. -#} Status: {{ node.code.name.lower() }}{% if node.own_code.name == 'MAINTENANCE' and node.reported_code.name not in ('MAINTENANCE', 'UNDEFINED') %} · {{ node.reported_code.name.lower() }}{% endif %} {%- if node.maintenance_entry %}
Silenced by {{ node.maintenance_entry.set_by or 'an admin' }} until {{ node.maintenance_entry.expires_at | localtime }}{% if node.maintenance_entry.reason and node.maintenance_entry.reason != 'maintenance' %} — {{ node.maintenance_entry.reason | markdown_inline }}{% endif %}
{%- endif %} {#- The dashboard's reason line, uncapped: every reason, and the same ``reason.actions`` slot (ADR-0034) beside each one, so a deployment's "raise a ticket" button is in both places the reason itself is. ``surface`` tells a filler which page it is on — this one is not polled. This is also the surface for **per-entry maintenance** (ADR-0036): where a check declared its reasons as members, an admin gets a pin control on each line, so the one finding somebody is working on can go quiet while its nineteen siblings keep alarming. A quiet line stays visible in the maintenance tint and says who silenced it and until when. Prose gets no per-line control — its unit of suppression is the node pin, and a per-line button there would offer to silence half of one condition. `?reason=` names one line (ADR-0036 decision 12): the maintenance index links here with it, because on a node with 150 findings arriving at the right *page* is not the same as arriving at the *line*. The named line — and only it — gets the `pinned-reason` id, so one anchor exists instead of one per reason, and only when it was asked for. -#} {%- if focus_orphan %} {#- The pin is real and its line is absent: a slug the current run did not report is **suspended, not deleted** (decision 6). Say so — this is the one surface that can, and an anchor that simply failed to scroll would have left the operator guessing. -#}
The line this pin was set on is no longer reported by this check. The pin is still here and still expires {{ focus_orphan.expires_at | localtime }}; if the line comes back, it comes back silenced.
{%- endif %} {% for line in node.reasons %} {%- set focused = focus and line.slug == focus %} {#- A coded line carries its own claim (ADR-0042): state class, its state's own tint, and a labeled cue as its accessible name; quiet keeps the maintenance tint over any code, and is-running is display only — the words still say it. -#}
{{ slot('reason.actions', node=node, reason=line.text, line=line, index=loop.index0, surface='check') }} {%- if is_admin and node.members %}
{% if line.quiet %}Edit maintenance{% else %}Set maintenance{% endif %}
{{ maintenance_fields( line.maintenance.reason if line.quiet else '', '', 'reason-maintenance-' ~ loop.index, maintenance_default, maintenance_timezone, true) }}
{%- if line.quiet %}
{%- endif %}
{%- endif %}
{% if line.code %}{{ status_cue(line.code, labeled=true) }}{% endif %}{{ line.text | markdown }}
{#- The record (backlog #32): what the check read about this line's subject, beside the sentence it wrote. A list of dotted names and values — its times in the configured timezone, everything else as stored — on the node's own page only: a card shows the line, and this is the surface a reader comes to when the line is not enough. -#} {%- if line.data %} {{ record_list(line.data) }} {#- Where the seam refused the record (ADR-0093), the line stands as its grading wrote it and this says why, in the record's place — escaped like any other data, since a why may quote the value it refused. -#} {%- elif line.refused %}

Record refused: {{ line.refused }}

{%- endif %} {%- if line.quiet %}
In maintenance{% if line.maintenance.set_by %}, set by {{ line.maintenance.set_by }}{% endif %} — expires {{ line.maintenance.expires_at | localtime }}.
{% if line.maintenance.reason and line.maintenance.reason != 'maintenance' %}
{{ line.maintenance.reason | markdown }}
{% endif %}
{%- endif %}
{% endfor %} {% if node.quiet_reasons %} {#- "nothing here is reporting" explains a node that went blue because its last member was pinned. Under a **node** pin it would take credit for the wrong thing — the banner above already says why — so the count then reports only what stays quiet once that pin is cleared. -#}
{{ node.quiet_reasons }} of {{ node.reasons | length }} {% if node.maintenance %}also pinned individually{% else %}in maintenance{% if node.own_code.name == 'MAINTENANCE' %} — nothing here is reporting{% endif %}{% endif %}.
{% endif %} {%- if node.damping %} {#- The counter, in words rather than as a number nobody can place: what this node shows, how far the count has got, and what its parent is counting meanwhile. The leaf is honest from the first failure (backlog #38 B) — what waits is only the claim that everything above is broken. -#}
Showing {{ node.damping.pending.name.lower() }} — {{ node.damping.seen }} of {{ node.damping.needed }} consecutive readings before this escalates{% if node.contribution and node.contribution.code %}, so the level above still counts {{ node.contribution.code.name.lower() }}{% endif %}.
{%- endif %} {% if node.stale %}
Stale — last checked {{ node.age_seconds | elapsed }} ago.
{% endif %}
{#- Take this node away. `/copy` hands over the whole tree; these two buttons hand over **this leaf**, with everything the tree document has no room for and only this page knows — the path, the observation and the period it bounds, the next update, the run's wall time, the frequency, the report, the configuration and every reason line in full, each instant naming its offset because the paste is read somewhere else. Directly under the status and the reasons, which is what the document is mostly made of. **Leaf pages only** — a container's page is a dashboard of its children, and the hand-off for a subtree already exists at `/copy`, so `_node_facts.html`, which both pages share, is deliberately not where this went. -#} {% include '_copy_controls.html' %} {#- Time, report and configuration — the shared node-facts block (_node_facts.html), which the branch page now renders too, so a container and a leaf say the same things in the same shapes (ADR-0044 decision 8). -#} {% include '_node_facts.html' %} {% if is_admin %} {% include '_maintenance_card.html' %} {% endif %}
{% include '_page_end.html' %} {# The clipboard writer, shared with /copy: same script, same two buttons, same fallbacks down to manual selection when the browser denies access. #}