{% extends 'generic/object.html' %} {% load helpers %} {% load i18n %} {% block content %}
{% trans "Change" %}
{% trans "Reference" %} {{ object.ref|placeholder }}
{% trans "Source" %} {{ object.source|linkify }}
{% trans "State" %} {% badge object.get_state_display bg_color=object.get_state_color %}
{% trans "Verdict" %} {% if object.verdict %} {% badge object.get_verdict_display bg_color=object.get_verdict_color %} {% else %} {% trans "Not yet verified" %} {% endif %}
{% trans "Requester" %} {{ object.requester|placeholder }}
{% trans "Priority" %} {{ object.priority }}
{% trans "Summary" %} {{ object.summary|placeholder }}
{% if perms.forward_netbox.change_forwardchange %} {% if transitions %}

{% trans "Move this change on:" %}

{% for move in transitions %}
{% csrf_token %}
{% endfor %} {% for move in transitions %} {% if not move.allowed and move.blockers %}
{{ move.target }}: {{ move.blockers|join:" " }}
{% endif %} {% endfor %} {% endif %} {% if object.state == 'verified-proceed' %}
{% csrf_token %}
{% endif %} {% endif %}
{% trans "Snapshots" %}
{# Pinned as literal ids, never selectors: verifying against a #} {# re-resolved snapshot would judge the change against a different #} {# network than the one it was approved against. #}
{% trans "Baseline (before)" %} {{ object.before_snapshot_id|placeholder }}
{% trans "Post-change (after)" %} {{ object.after_snapshot_id|placeholder }}
{% trans "Branch" %} {{ object.branch_name|placeholder }}
{% trans "Applied" %}

{% trans "Attested, not measured. Nothing here can observe the network being changed, so this is a human claim about when it happened." %}

{% trans "When" %} {{ object.applied_at|placeholder }}
{% trans "Attested by" %} {{ object.applied_by|placeholder }}
{% trans "Reference" %} {{ object.applied_ref|placeholder }}
{% if perms.forward_netbox.change_forwardchange and object.state == 'approved' %}
{% csrf_token %}
{% endif %}
{% trans "Criteria" %}

{% trans "Each criterion is an NQE query and what to expect of it. It is bound to a committed query version before anything is measured, and cannot change once evidence exists." %}

{% if criteria %} {% for criterion in criteria %} {% endfor %}
{{ criterion.name }}{% if not criterion.blocking %} {% trans "advisory" %}{% endif %} {{ criterion.get_expectation_display }} {% if criterion.is_bound %} {% trans "bound" %} {% else %} {% trans "not bound" %} {% endif %} {% if perms.forward_netbox.change_forwardchangecriterion %}
{% csrf_token %}
{% trans "Edit" %} {% endif %} {% if perms.forward_netbox.delete_forwardchangecriterion %}
{% csrf_token %}
{% endif %}
{% else %}

{% trans "No criteria yet." %}

{% endif %} {% if perms.forward_netbox.add_forwardchangecriterion %} {% trans "Add criterion" %} {% endif %}
{% trans "Evidence" %}

{% trans "This is what the verdict is computed from, and the only thing it is computed from." %}

{% if criterion_outcomes %} {% for outcome in criterion_outcomes %} {% endfor %}
{% trans "Criterion" %} {% trans "Before" %} {% trans "After" %} {% trans "Result" %}
{{ outcome.criterion.name }} {% if not outcome.blocking %} {% trans "advisory" %} {% endif %} {% checkmark outcome.before_passed %} {% checkmark outcome.after_passed %} {% if outcome.flip %} {% if outcome.blocks %} {% trans "regression" %} {% else %} {{ outcome.flip }} {% endif %} {% else %} {# Never rendered as a pass. A criterion nobody #} {# evaluated is not a criterion that passed. #} {% trans "not measured" %} {% endif %}
{% else %}

{% trans "No criteria have been evaluated. A change with nothing asserted cannot be verified, only asserted to have happened." %}

{% endif %}
{% trans "Validation" %}

{% trans "Rules from the validation policies that apply to this change, run in its workspace. A run counts only against the snapshots the change is pinned to now." %}

{% if validation_gate %}
{% for blocker in validation_gate %}
{{ blocker }}
{% endfor %}
{% endif %} {% if validation_runs %} {% for run in validation_runs %} {% endfor %}
#{{ run.pk }} {% badge run.get_status_display bg_color=run.get_status_color %} {% if run.score is None %}{% trans "no score" %}{% else %}{{ run.score }}{% endif %} {{ run.created|date:"Y-m-d H:i" }}
{% else %}

{% trans "No validation runs yet." %}

{% endif %} {% if can_validate %}
{% csrf_token %}
{% endif %}
{% trans "What Forward allows here" %}

{% trans "Found by asking Forward with read-only calls, never from a licence table." %}

{% if capabilities %} {% for label, text, available in capabilities %} {% endfor %}
{{ label }} {{ text }}
{% endif %}
{% csrf_token %}
{{ predict_panel.heading }}
{# Advisory, and separated from Evidence above on purpose. An #} {# advisory panel that looks like evidence is how a prediction #} {# quietly becomes a decision. #}

{% trans "Advisory only. The verdict does not depend on this." %}

{{ predict_panel.message }}

{% trans "Scope" %}
{% if scoped_devices %}
    {% for scoped in scoped_devices %}
  • {{ scoped.device|linkify }} {% if scoped.forward_device_key %} {{ scoped.forward_device_key }} {% else %} {% trans "no Forward identity" %} {% endif %} {% if perms.forward_netbox.change_forwardchange and not object.workspace_network_id %}
    {% csrf_token %}
    {% endif %}
  • {% endfor %}
{% else %}

{% trans "No devices in scope." %}

{% endif %} {% if perms.forward_netbox.change_forwardchange and not object.workspace_network_id %}
{% csrf_token %}
{% if scoped_devices %}
{% csrf_token %}
{% endif %} {% endif %}
{% trans "Forward workspace and verification" %}
{# The workspace holds only this change's devices; queries run on it, at #} {# the baseline it was forked with and a collection made after the apply. #}
{% trans "Workspace" %} {% if object.workspace_network_id %} {{ object.workspace_network_id }} ({{ object.workspace_origin }}) {% else %} {% trans "none yet" %} {% endif %}
{% trans "Baseline snapshot" %} {{ object.before_snapshot_id|placeholder }}
{% trans "After snapshot" %} {{ object.after_snapshot_id|placeholder }}
{% if perms.forward_netbox.change_forwardchange %} {% if not object.workspace_network_id %}
{% csrf_token %}
{% csrf_token %}
{% else %}
{% csrf_token %}
{% csrf_token %}
{% csrf_token %}
{% endif %} {% endif %}
{% trans "Reviews" %}
{# Two gates. The pre gate approves the PLAN; the post gate approves #} {# the CLOSURE, which is where the branch actually merges. A PROCEED #} {# verdict opens that gate rather than walking through it. #} {% if reviews %} {% for review in reviews %} {% endfor %}
{{ review.reviewer|placeholder }} {{ review.phase }} {% if review.approved %} {% trans "approved" %} {% else %} {% trans "rejected" %} {% endif %} {{ review.comment }}
{% else %}

{% trans "No reviews yet." %}

{% endif %} {% if perms.forward_netbox.approve_forwardchange %}
{% csrf_token %}
{% endif %}
{% trans "Comments" %}
{% for comment in comments %}
{{ comment.author|placeholder }} ยท {{ comment.created|date:"Y-m-d H:i" }} {% if comment.resolved %} {% trans "resolved" %} {% endif %}
{{ comment.body|linebreaksbr }}
{% for reply in comment.replies.all %}
{{ reply.author|placeholder }}: {{ reply.body|linebreaksbr }}
{% csrf_token %} {% if request.user.is_authenticated and reply.author_id == request.user.pk %} {% endif %}
{% endfor %} {% if can_reply %}
{% csrf_token %}
{% endif %}
{% if can_resolve %}
{% csrf_token %}
{% endif %} {% if request.user.is_authenticated and comment.author_id == request.user.pk and not comment.replies.all %}
{% csrf_token %}
{% endif %}
{% empty %}

{% trans "No comments yet." %}

{% endfor %} {% if can_comment %}
{% csrf_token %}
{% endif %}
{% trans "Next steps" %}
{% if transitions %} {% for transition in transitions %} {% endfor %}
{{ transition.target }} {% if transition.allowed %} {% trans "ready" %} {% else %}
    {% for blocker in transition.blockers %}
  • {{ blocker }}
  • {% endfor %}
{% endif %}
{% else %}

{% trans "This change is finished; there is nowhere further to go." %}

{% endif %}
{% endblock content %}