From 304611054cb5d6cace9197ab5ad1913a8bd7b5f7 Mon Sep 17 00:00:00 2001 From: Anton Krivoborodov Date: Fri, 18 Sep 2026 09:19:27 +0000 Subject: [PATCH] feat: split platform-scoped features out of module_verification_report module_verification_report previously rendered both the module's own components AND every Feature reachable from those components, mixing module-scoped and platform-scoped statistics into a single report. - module_verification_report.need: drop the feature-loop section (Requirements/Architecture/Inspection Statistics per Feature). The report now covers Components only, as its name implies. - platform_verification_report.need (new): the feature-scoped counterpart, listing every Feature in the current build (via the existing needs_of_type("feat") helper) with the same statistics that were removed from the module report. --- .../module_verification_report.need | 137 +------------ .../platform_verification_report.need | 194 ++++++++++++++++++ 2 files changed, 201 insertions(+), 130 deletions(-) create mode 100644 src/needs_templates/platform_verification_report.need diff --git a/src/needs_templates/module_verification_report.need b/src/needs_templates/module_verification_report.need index 64bbbcea8..d2f25cb0f 100644 --- a/src/needs_templates/module_verification_report.need +++ b/src/needs_templates/module_verification_report.need @@ -6,10 +6,13 @@ The report is a ``document`` need whose id encodes the module it covers (``doc___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 @@ -22,16 +25,6 @@ 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"], @@ -39,10 +32,6 @@ ["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 @@ -88,118 +77,6 @@ .wp-doc-table td .dataTables_wrapper .dataTables_paginate { display: none; } -{#- ===================================================================== -#} -{#- 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 #} {# ===================================================================== #} diff --git a/src/needs_templates/platform_verification_report.need b/src/needs_templates/platform_verification_report.need new file mode 100644 index 000000000..271109350 --- /dev/null +++ b/src/needs_templates/platform_verification_report.need @@ -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 + + + +{# ===================================================================== #} +{# 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 + +
+ +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 %}