Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 7 additions & 130 deletions src/needs_templates/module_verification_report.need
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
The report is a ``document`` need whose id encodes the module it covers
(``doc__<module>_verification_report``) — the ``document`` type has no
``belongs_to`` link, so the module id is recovered from this need's own id
instead. The module's ``includes`` links provide the components, and each
component's ``belongs_to`` link provides the feature. The ``linked_needs``
helper resolves this graph during the post-collection reread, so titles and
report sections stay driven by the Need model.
instead. The module's ``includes`` links provide the components. The
``linked_needs`` helper resolves this graph during the post-collection
reread, so titles and report sections stay driven by the Need model.

This report is module- and component-scoped only. The platform-wide,
feature-scoped counterpart (all Features and their statistics) lives in the
sibling ``platform_verification_report`` template.

The template is applied as ``:post_template:``, not ``:template:``. A need's
*content* cannot open new sections ("Unexpected section title"), but
Expand All @@ -22,27 +25,13 @@
may list a component more than once, so deduplicate the NeedItems by ID. #}
{% set components_in_mod = linked_needs(module_id, "includes")|unique(attribute="id")|list %}

{# Collect every feature reachable from the module's components. A feature can
be linked by multiple components, so collect all candidates first and then
keep each feature NeedItem only once in first-seen graph order. The
namespace is required because assignments inside a Jinja loop are scoped. #}
{% set feature_candidates = namespace(items=[]) %}
{% for component in components_in_mod %}
{% set feature_candidates.items = feature_candidates.items + linked_needs(component["id"], "belongs_to") %}
{% endfor %}
{% set report_features = feature_candidates.items|unique(attribute="id")|list %}

{% set component_workproducts = [
["wp__requirements_inspect", "Requirements Inspection"],
["wp__sw_arch_verification", "Architecture Inspection"],
["wp__sw_implementation_inspection", "Implementation Inspection"],
["wp__sw_component_dfa", "DFA"],
["wp__sw_component_fmea", "FMEA"],
] %}
{% set feature_workproducts = [
["wp__requirements_inspect", "Requirements Inspection"],
["wp__sw_arch_verification", "Architecture Inspection"],
] %}

{#- One work-product row: the need link, its kind, the realising document and
its status. Both cells are needtables over the same filter, differing only
Expand Down Expand Up @@ -88,118 +77,6 @@
.wp-doc-table td .dataTables_wrapper .dataTables_paginate { display: none; }
</style>

{#- ===================================================================== -#}
{#- Feature sections resolved from all components' belongs_to links. -#}
{#- ===================================================================== -#}
{% for report_feature in report_features %}
{% set feature_id = report_feature["id"] %}
{% set feature_title = report_feature["title"] %}
{# Derive the work-product document selector from the feature Need reached
through the graph, rather than reconstructing it from the module ID. #}
{% set feature_slug_norm = feature_title|replace("_", "")|replace(" ", "")|lower %}
{% set feature_heading = feature_title if report_features|length == 1 else "Feature: " ~ feature_title %}

{{ feature_heading }}
{{ "-" * (feature_heading|length) }}

.. needtable::
:filter: id == "{{ feature_id }}"
:columns: title as "Name";id as "Id";safety;security;status
:style: table

Requirements Statistics
~~~~~~~~~~~~~~~~~~~~~~~

.. grid:: 1 2 2 2
:gutter: 3

.. grid-item::

.. needpie:: Feature Requirements Status
:labels: valid, invalid
:colors: #37a12d, #ca2828
:legend:

type == "feat_req" and "{{ feature_id }}" in satisfied_by and status == "valid"
type == "feat_req" and "{{ feature_id }}" in satisfied_by and status == "invalid"

.. grid-item::

.. needpie:: Feature Requirements Test Coverage
:labels: fully covered, partially covered, not covered
:colors: #37a12d, #f0a500, #ca2828
:legend:

type == "feat_req" and "{{ feature_id }}" in satisfied_by and fully_verifies_back
type == "feat_req" and "{{ feature_id }}" in satisfied_by and partially_verifies_back and not fully_verifies_back
type == "feat_req" and "{{ feature_id }}" in satisfied_by and not fully_verifies_back and not partially_verifies_back

.. dropdown:: Show requirements table
:animate: fade-in

.. needtable::
:filter: type == "feat_req" and "{{ feature_id }}" in satisfied_by
:style: table
:columns: id;title;safety;status;testlink
:colwidths: 13,22,8,10,47
:sort: id

Architecture Statistics
~~~~~~~~~~~~~~~~~~~~~~~

.. grid:: 1 2 2 2
:gutter: 3

.. grid-item::

.. needpie:: Feature Architecture Elements Status
:labels: valid, invalid
:colors: #37a12d, #ca2828
:legend:

type in ["feat_arc_sta", "feat_arc_dyn"] and "{{ feature_id }}" in belongs_to and status == "valid"
type in ["feat_arc_sta", "feat_arc_dyn"] and "{{ feature_id }}" in belongs_to and status == "invalid"

.. grid-item::

.. needpie:: Feature Architecture Elements Inspection Status
:labels: inspected, not inspected
:colors: #37a12d, #ca2828
:legend:

type in ["feat_arc_sta", "feat_arc_dyn"] and "{{ feature_id }}" in belongs_to and "inspected" in tags
type in ["feat_arc_sta", "feat_arc_dyn"] and "{{ feature_id }}" in belongs_to and "inspected" not in tags

.. dropdown:: Show architectural elements table
:animate: fade-in

.. needtable::
:filter: type in ["feat_arc_sta", "feat_arc_dyn"] and "{{ feature_id }}" in belongs_to
:style: table
:columns: id;title;safety;status;tags
:colwidths: 25,30,10,15,20
:sort: id

Inspection Statistics
~~~~~~~~~~~~~~~~~~~~~

Presence of the feature-level inspection work products.

.. dropdown:: Show work products table
:animate: fade-in

.. list-table::
:header-rows: 1
:widths: 30 25 25 20
:class: wp-doc-table

* - Work Product
- Kind
- Realized by
- Status
{{ workproduct_rows(feature_slug_norm, feature_workproducts) }}
{% endfor %}

{# ===================================================================== #}
{# Components #}
{# ===================================================================== #}
Expand Down
194 changes: 194 additions & 0 deletions src/needs_templates/platform_verification_report.need
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
{#
score: render-after-needs-collection

Content template for the ``document`` need type for ``platform_verification_report``.

Unlike ``module_verification_report``, this report is not scoped to a single
module: it collects every Feature in the current build's Need graph via the
``needs_of_type`` helper, so it always reflects the full platform surface
regardless of which document instantiates it. This is the platform-wide,
feature-scoped counterpart to ``module_verification_report``'s
module-and-component-scoped report.

The template is applied as ``:post_template:``, not ``:template:``. A need's
*content* cannot open new sections ("Unexpected section title"), but
post-content is placed after the need at document level, where real headings
work — and real headings are what give the report its TOC entries and
per-feature navigation.
#}
{% set report_features = needs_of_type("feat")|unique(attribute="id")|sort(attribute="title")|list %}

{% set feature_workproducts = [
["wp__requirements_inspect", "Requirements Inspection"],
["wp__sw_arch_verification", "Architecture Inspection"],
] %}

{#- One work-product row: the need link, its kind, the realising document and
its status. Both cells are needtables over the same filter, differing only
in :columns:, so an empty match renders as an empty cell. -#}
{% macro workproduct_rows(slug_norm, workproducts) %}
{%- for wp in workproducts %}
* - :need:`{{ wp[0] }}`
- {{ wp[1] }}
- .. needtable::
:filter: type == "document" and "{{ slug_norm }}" in id.replace("_", "").lower() and "{{ wp[0] }}" in realizes
:columns: id
:style: table
- .. needtable::
:filter: type == "document" and "{{ slug_norm }}" in id.replace("_", "").lower() and "{{ wp[0] }}" in realizes
:columns: status
:style: table
{%- endfor %}
{% endmacro %}

.. raw:: html

<style>
.wp-doc-table td .needstable_wrapper,
.wp-doc-table td .pst-scrollable-table-container {
margin: 0; padding: 0; overflow: visible;
}
.wp-doc-table td table.NEEDS_TABLE,
.wp-doc-table td table.NEEDS_DATATABLES {
border: 0; margin: 0; box-shadow: none; background: transparent;
width: auto;
}
.wp-doc-table td table.NEEDS_TABLE thead,
.wp-doc-table td table.NEEDS_DATATABLES thead { display: none; }
.wp-doc-table td table.NEEDS_TABLE tbody tr,
.wp-doc-table td table.NEEDS_DATATABLES tbody tr { background: transparent; }
.wp-doc-table td table.NEEDS_TABLE tbody td,
.wp-doc-table td table.NEEDS_DATATABLES tbody td {
border: 0; padding: 0; background: transparent;
}
.wp-doc-table td .dataTables_wrapper .dataTables_length,
.wp-doc-table td .dataTables_wrapper .dataTables_filter,
.wp-doc-table td .dataTables_wrapper .dataTables_info,
.wp-doc-table td .dataTables_wrapper .dataTables_paginate { display: none; }
</style>

{# ===================================================================== #}
{# Features #}
{# ===================================================================== #}

Features
--------

Feature Overview
~~~~~~~~~~~~~~~~

.. needtable::
:filter: id in [{% for feature in report_features %}"{{ feature["id"] }}"{% if not loop.last %}, {% endif %}{% endfor %}]
:columns: id as "Feature";safety;security;status
:style: table
:sort: id

{% for feature in report_features %}
{% set feature_id = feature["id"] %}
{% set feature_title = feature["title"] %}
{# The feature Need supplies the work-product document selector and the
navigation anchor, the same way components do in module_verification_report. #}
{% set feature_slug_norm = feature_title|replace("_", "")|replace(" ", "")|lower %}
{% set feature_anchor = feature_title|replace("_", "-")|replace(" ", "-")|lower %}

.. _feat-{{ feature_anchor }}:

{{ feature_title }}
{{ "~" * (feature_title|length) }}

.. raw:: html

<hr style="border-top: 2px solid #333333; margin: 0.5em 0 1.5em 0;">

Requirements Statistics
^^^^^^^^^^^^^^^^^^^^^^^

.. grid:: 1 2 2 2
:gutter: 3

.. grid-item::

.. needpie:: {{ feature_title }} Requirements Status
:labels: valid, invalid
:colors: #37a12d, #ca2828
:legend:

type == "feat_req" and "{{ feature_id }}" in satisfied_by and status == "valid"
type == "feat_req" and "{{ feature_id }}" in satisfied_by and status == "invalid"

.. grid-item::

.. needpie:: {{ feature_title }} Requirements Test Coverage
:labels: fully covered, partially covered, not covered
:colors: #37a12d, #f0a500, #ca2828
:legend:

type == "feat_req" and "{{ feature_id }}" in satisfied_by and fully_verifies_back
type == "feat_req" and "{{ feature_id }}" in satisfied_by and partially_verifies_back and not fully_verifies_back
type == "feat_req" and "{{ feature_id }}" in satisfied_by and not fully_verifies_back and not partially_verifies_back

.. dropdown:: Show requirements table
:animate: fade-in

.. needtable::
:filter: type == "feat_req" and "{{ feature_id }}" in satisfied_by
:style: table
:columns: id;title;safety;status;testlink
:colwidths: 13,22,8,10,47
:sort: id

Architecture Statistics
^^^^^^^^^^^^^^^^^^^^^^^

.. grid:: 1 2 2 2
:gutter: 3

.. grid-item::

.. needpie:: {{ feature_title }} Architecture Elements Status
:labels: valid, invalid
:colors: #37a12d, #ca2828
:legend:

type in ["feat_arc_sta", "feat_arc_dyn"] and "{{ feature_id }}" in belongs_to and status == "valid"
type in ["feat_arc_sta", "feat_arc_dyn"] and "{{ feature_id }}" in belongs_to and status == "invalid"

.. grid-item::

.. needpie:: {{ feature_title }} Architecture Elements Inspection Status
:labels: inspected, not inspected
:colors: #37a12d, #ca2828
:legend:

type in ["feat_arc_sta", "feat_arc_dyn"] and "{{ feature_id }}" in belongs_to and "inspected" in tags
type in ["feat_arc_sta", "feat_arc_dyn"] and "{{ feature_id }}" in belongs_to and "inspected" not in tags

.. dropdown:: Show architectural elements table
:animate: fade-in

.. needtable::
:filter: type in ["feat_arc_sta", "feat_arc_dyn"] and "{{ feature_id }}" in belongs_to
:style: table
:columns: id;title;safety;status;tags
:colwidths: 25,30,10,15,20
:sort: id

Inspection Statistics
^^^^^^^^^^^^^^^^^^^^^

Presence of the feature-level inspection work products.

.. dropdown:: Show work products table
:animate: fade-in

.. list-table::
:header-rows: 1
:widths: 30 25 25 20
:class: wp-doc-table

* - Work Product
- Kind
- Realized by
- Status
{{ workproduct_rows(feature_slug_norm, feature_workproducts) }}
{% endfor %}
Loading