From 078211bb21fbe77bb2d1c903613059d53a3d05b3 Mon Sep 17 00:00:00 2001 From: Jochen Hoenle <173445474+hoe-jo@users.noreply.github.com> Date: Thu, 24 Sep 2026 12:14:44 +0200 Subject: [PATCH] [rules score] update safety analysis - rename fmea to safety analysis - adapt documentation of safety analysis --- .github/skills/rules-score/SKILL.md | 6 +- .github/skills/score-safety-analysis/SKILL.md | 2 +- bazel/rules/rules_score/BUILD | 12 +- bazel/rules/rules_score/README.md | 12 +- .../docs/_assets/rules_score_overview.puml | 8 +- .../_assets/safety_analysis_doc_pipeline.puml | 26 +- .../rules_score/docs/_assets/seooc_flow.puml | 10 +- .../docs/_assets/tooling_chain.puml | 10 +- .../rules_score/docs/integration_guide.rst | 6 +- bazel/rules/rules_score/docs/overview.rst | 4 +- .../docs/requirements/tool_requirements.trlc | 2 +- .../rules/rules_score/docs/rule_reference.rst | 32 +- .../rules_score/docs/tooling_architecture.rst | 59 +- .../docs/user_guide/architectural_design.rst | 73 +-- .../user_guide/dependability_analysis.rst | 530 +++++++++--------- bazel/rules/rules_score/examples/seooc/BUILD | 2 +- .../examples/seooc/safety_analysis/BUILD | 10 +- ...ple_safety_analysis_control_measures.trlc} | 0 ...sample_safety_analysis_failure_modes.trlc} | 0 bazel/rules/rules_score/lobster/config/BUILD | 2 +- .../private/dependability_analysis.bzl | 30 +- .../private/{fmea.bzl => safety_analysis.bzl} | 56 +- bazel/rules/rules_score/providers.bzl | 4 +- bazel/rules/rules_score/rules_score.bzl | 10 +- ...embler.py => safety_analysis_assembler.py} | 6 +- ...plate.rst => safety_analysis.template.rst} | 0 bazel/rules/rules_score/test/BUILD | 30 +- .../dynamic_public_api_failure_modes.trlc | 2 +- .../dynamic_public_api_fta.puml | 2 +- .../public_api_failure_modes.trlc | 2 +- .../clickable_example/public_api_fta.puml | 2 +- ...r.py => test_safety_analysis_assembler.py} | 40 +- plantuml/parser/puml_fta/src/lib.rs | 2 +- 33 files changed, 470 insertions(+), 522 deletions(-) rename bazel/rules/rules_score/examples/seooc/safety_analysis/{sample_fmea_control_measures.trlc => sample_safety_analysis_control_measures.trlc} (100%) rename bazel/rules/rules_score/examples/seooc/safety_analysis/{sample_fmea_failure_modes.trlc => sample_safety_analysis_failure_modes.trlc} (100%) rename bazel/rules/rules_score/private/{fmea.bzl => safety_analysis.bzl} (87%) rename bazel/rules/rules_score/src/{fmea_assembler.py => safety_analysis_assembler.py} (98%) rename bazel/rules/rules_score/templates/{fmea.template.rst => safety_analysis.template.rst} (100%) rename bazel/rules/rules_score/test/{test_fmea_assembler.py => test_safety_analysis_assembler.py} (90%) diff --git a/.github/skills/rules-score/SKILL.md b/.github/skills/rules-score/SKILL.md index 5d9a5bd6..e6dfae02 100644 --- a/.github/skills/rules-score/SKILL.md +++ b/.github/skills/rules-score/SKILL.md @@ -40,7 +40,7 @@ Use this skill to coordinate; open the specialized skill for the actual work: | `.trlc` requirement records, `ScoreReq` model, traceability, `assumed_system_requirements` / `feature_requirements` / `component_requirements` / `assumptions_of_use` | **score-requirements** | | PlantUML diagrams, `architectural_design` / `unit` / `unit_design` / `component` / `dependable_element` structure, architecture/API/sequence validations | **score-architecture** | | GoogleTest `lobster-tracing` + Given-When-Then, `test_case_coverage.lock.yaml`, attaching tests | **score-testing** | -| FMEA, `FailureMode` / `ControlMeasure` / FTA, `fmea` / `dependability_analysis` | **score-safety-analysis** | +| FMEA, `FailureMode` / `ControlMeasure` / FTA, `safety_analysis` / `dependability_analysis` | **score-safety-analysis** | --- @@ -59,7 +59,7 @@ with a traceability report. | Architectural Design | `architectural_design` | score-architecture | | Units & Components | `unit`, `unit_design`, `component` | score-architecture | | Tests & Coverage | `tests` attr, `test_case_coverage_lock` | score-testing | -| Dependability Analysis | `fmea`, `dependability_analysis` | score-safety-analysis | +| Dependability Analysis | `safety_analysis`, `dependability_analysis` | score-safety-analysis | | SEooC assembly | `dependable_element` | this skill | ### Hierarchy @@ -182,7 +182,7 @@ FMEA, cross-module `deps`, and test-case coverage — see 3. **Implementation & tests** → back each `unit` with a `cc_library` + `cc_test`; annotate tests with `lobster-tracing` + Given-When-Then; add `test_case_coverage_lock` on components. *(score-testing)* -4. **Safety analysis** → add `fmea` (FailureMode + ControlMeasure + FTA) and wrap it in a +4. **Safety analysis** → add `safety_analysis` (FailureMode + ControlMeasure + FTA) and wrap it in a `dependability_analysis`. *(score-safety-analysis)* 5. **Assemble** → allocate `CompReq` to `component(requirements=…)` and `FeatReq` to `dependable_element(requirements=…)`; wire `architectural_design`, `components`, diff --git a/.github/skills/score-safety-analysis/SKILL.md b/.github/skills/score-safety-analysis/SKILL.md index df766ad2..0d63b01e 100644 --- a/.github/skills/score-safety-analysis/SKILL.md +++ b/.github/skills/score-safety-analysis/SKILL.md @@ -34,7 +34,7 @@ score//dependability/ │ ├── failure_modes.trlc # FailureMode records (one per unique root-cause cluster) │ ├── control_measures.trlc # ControlMeasure / PreventiveMeasure / AoU records │ ├── fta_.puml # One FTA diagram per FailureMode -│ └── BUILD # fmea() rule — must list all .puml in fta_files filegroup +│ └── BUILD # safety_analysis() rule — must list all .puml in fta_files filegroup ├── assumed_system/ │ └── aous.trlc # AoU records (caller obligations) └── requirements/ diff --git a/bazel/rules/rules_score/BUILD b/bazel/rules/rules_score/BUILD index 47792d8e..9b08f4ec 100644 --- a/bazel/rules/rules_score/BUILD +++ b/bazel/rules/rules_score/BUILD @@ -38,7 +38,7 @@ exports_files([ "templates/section_page.template.rst", "templates/unit.template.rst", "templates/component.template.rst", - "templates/fmea.template.rst", + "templates/safety_analysis.template.rst", "templates/puml_diagram.template.rst", ]) @@ -88,13 +88,13 @@ py_binary( visibility = ["//visibility:public"], ) -# FMEA page assembler: builds the failure-mode-centric fmea.rst body in-process -# via the extended TRLCRST library and the FTA chains JSON from puml_cli. +# Safety-analysis page assembler: builds the failure-mode-centric safety_analysis.rst body +# in-process via the extended TRLCRST library and the FTA chains JSON from puml_cli. py_binary( - name = "fmea_assembler", - srcs = ["src/fmea_assembler.py"], + name = "safety_analysis_assembler", + srcs = ["src/safety_analysis_assembler.py"], imports = ["src"], - main = "src/fmea_assembler.py", + main = "src/safety_analysis_assembler.py", visibility = ["//visibility:public"], deps = [ "@trlc//tools/trlc_rst:trlc_rst_lib", diff --git a/bazel/rules/rules_score/README.md b/bazel/rules/rules_score/README.md index 36b58507..9bf58160 100644 --- a/bazel/rules/rules_score/README.md +++ b/bazel/rules/rules_score/README.md @@ -28,7 +28,7 @@ for safety related automotive software. | `architectural_design` | `ArchitecturalDesignInfo` | | `unit` | `UnitInfo`, `CertifiedScope` | | `component` | `ComponentInfo` | -| `fmea` | `AnalysisInfo` | +| `safety_analysis` | `AnalysisInfo` | | `glossary` | `SphinxSourcesInfo` | | `dependability_analysis` | `DependabilityAnalysisInfo` | | `dependable_element` | HTML documentation zip (Sphinx) | @@ -137,11 +137,11 @@ and collects requirement + architecture + test lobster sources. --- -## `fmea` +## `safety_analysis` ```starlark -fmea( - name = "my_fmea", +safety_analysis( + name = "my_safety_analysis", failuremodes = [":failure_modes"], controlmeasures = [":control_measures"], root_causes = ["fta.puml"], @@ -149,7 +149,7 @@ fmea( ) ``` -**`bazel build`** — generates `fmea.rst` (merged FM / CM / FTA sections), +**`bazel build`** — generates `safety_analysis.rst` (merged FM / CM / FTA sections), runs `lobster-trlc` on TRLC inputs, and extracts FTA events from `.puml` diagrams into `fta.lobster`. Build-only; traceability validation is done by the wrapping `dependability_analysis` test. @@ -212,7 +212,7 @@ dependable_element( ```starlark dependability_analysis( name = "my_da", - fmea = [":my_fmea"], + safety_analysis = [":my_safety_analysis"], arch_design = ":my_design", ) ``` diff --git a/bazel/rules/rules_score/docs/_assets/rules_score_overview.puml b/bazel/rules/rules_score/docs/_assets/rules_score_overview.puml index bddea3e9..5fdfda6a 100644 --- a/bazel/rules/rules_score/docs/_assets/rules_score_overview.puml +++ b/bazel/rules/rules_score/docs/_assets/rules_score_overview.puml @@ -44,8 +44,8 @@ component "assumptions_of_use" <> as aou component "unit" <> as unit component "component" <> as comp -' ── Safety Analysis rules ───────────────────────────────────────────────────── -component "fmea" <> as fmea +' ── Safety Analysis rules ────────────────────────────────────────────────────────── +component "safety_analysis" <> as safety_analysis component "dependability_analysis" <> as da ' ── Documentation rules ─────────────────────────────────────────────────────── @@ -56,7 +56,7 @@ component "dependable_element" as de unit_design --> unit : <> -arch --> fmea : <> +arch --> safety_analysis : <> arch --> de : <> feat_req --> aou : <> @@ -65,7 +65,7 @@ feat_req --> de : <> comp_req --> comp : <> comp_req --> aou : <> -fmea --> da : <> +safety_analysis --> da : <> da --> de : <> aou --> de : <> diff --git a/bazel/rules/rules_score/docs/_assets/safety_analysis_doc_pipeline.puml b/bazel/rules/rules_score/docs/_assets/safety_analysis_doc_pipeline.puml index 21884adf..e4a4d1d4 100644 --- a/bazel/rules/rules_score/docs/_assets/safety_analysis_doc_pipeline.puml +++ b/bazel/rules/rules_score/docs/_assets/safety_analysis_doc_pipeline.puml @@ -13,8 +13,8 @@ @startuml safety_analysis_doc_pipeline -' Component view of the FMEA build: input artifacts (authored + tooling -' defaults) flow through three in-process tool actions of the ``fmea`` rule into +' Component view of the safety-analysis build: input artifacts (authored + tooling +' defaults) flow through three in-process tool actions of the ``safety_analysis`` rule into ' the generated files, the providers, and finally the Sphinx staging tree. skinparam linetype ortho @@ -49,14 +49,14 @@ package "Authored by the component team" { package "Tooling defaults (rules_score / ScoreReq)" { rectangle "ScoreReq *.rsl\n(spec attr)" <> as rsl rectangle "fta_metamodel.puml\n(on PlantUML include path)" <> as meta - rectangle "fmea.template.rst\n({body})" <> as tmpl + rectangle "safety_analysis.template.rst\n({body})" <> as tmpl rectangle "fm/cm lobster\nconfigs" <> as lcfg } -' ── fmea rule: three tool actions ──────────────────────────────────────────── -package "fmea rule actions" { +' ── safety_analysis rule: three tool actions ─────────────────────────────────────────── +package "safety_analysis rule actions" { component "puml_cli (FTA mode)\n--fta-output-dir\n[crate: puml_fta]" <> as puml - component "fmea_assembler\n[lib: TRLCRST]" <> as asm + component "safety_analysis_assembler\n[lib: TRLCRST]" <> as asm component "lobster-trlc x2" <> as ltrlc } @@ -65,18 +65,18 @@ package "Generated files" { rectangle "fta_*.puml\n(authored, symlinked)" <> as puml_inl rectangle "fta_chains.json" <> as chains rectangle "root_causes.lobster" <> as rc_lob - rectangle "fmea.rst" <> as fmea_rst + rectangle "safety_analysis.rst" <> as sa_rst rectangle "failuremodes.lobster\ncontrolmeasures.lobster" <> as fmcm_lob } ' ── Providers ──────────────────────────────────────────────────────────────── -rectangle "SphinxSourcesInfo\n────────────────\nsrcs: fmea.rst\ndeps: fmea.rst\naux_srcs: fta_*.puml" <> as ssi +rectangle "SphinxSourcesInfo\n────────────────\nsrcs: safety_analysis.rst\ndeps: safety_analysis.rst\naux_srcs: fta_*.puml" <> as ssi rectangle "AnalysisInfo.lobster_files\n────────────────\nfailuremodes.lobster\ncontrolmeasures.lobster\nroot_causes.lobster" <> as ai ' ── Downstream rules + staging ─────────────────────────────────────────────── component "dependability_analysis" <> as da component "dependable_element" <> as de -rectangle "dependability_analysis/\n dfa.rst <- toctree\n fmea.rst <- toctree\n fta_*.puml (.. uml::)" <> as stage +rectangle "dependability_analysis/\n dfa.rst <- toctree\n safety_analysis.rst <- toctree\n fta_*.puml (.. uml::)" <> as stage ' ── Edges: inputs -> tools ─────────────────────────────────────────────────── fta_puml --> puml : parse macro calls @@ -93,15 +93,15 @@ rsl --> ltrlc lcfg --> ltrlc ' ── Edges: tools -> generated ──────────────────────────────────────────────── -fta_puml --> puml_inl : symlinked beside fmea.rst +fta_puml --> puml_inl : symlinked beside safety_analysis.rst meta --> stage : on PlantUML include path puml --> chains puml --> rc_lob -asm --> fmea_rst +asm --> sa_rst ltrlc --> fmcm_lob -' ── Edges: generated -> providers ──────────────────────────────────────────── -fmea_rst --> ssi +' ── Edges: generated -> providers ───────────────────────────────────────────────────── +sa_rst --> ssi puml_inl --> ssi rc_lob --> ai fmcm_lob --> ai diff --git a/bazel/rules/rules_score/docs/_assets/seooc_flow.puml b/bazel/rules/rules_score/docs/_assets/seooc_flow.puml index ba783425..4396d6a4 100644 --- a/bazel/rules/rules_score/docs/_assets/seooc_flow.puml +++ b/bazel/rules/rules_score/docs/_assets/seooc_flow.puml @@ -49,7 +49,7 @@ rectangle "architectural_design" <> as arch_r rectangle "unit_design" <> as ud_r rectangle "unit" <> as unit_r rectangle "component" <> as comp_r2 -rectangle "fmea" <> as fmea_r +rectangle "safety_analysis" <> as safety_analysis_r rectangle "dependability_analysis" <> as da_r rectangle "dependable_element" <> as de_r @@ -65,9 +65,9 @@ arch_in --> arch_r ud_in --> ud_r impl_in --> unit_r tests_in --> unit_r -fm_in --> fmea_r -cm_in --> fmea_r -fta_in --> fmea_r +fm_in --> safety_analysis_r +cm_in --> safety_analysis_r +fta_in --> safety_analysis_r asr_r --> feat_r : deps asr_r --> aou_r @@ -77,7 +77,7 @@ comp_r --> comp_r2 : requirements ud_r --> unit_r : unit_design unit_r --> comp_r2 : components -fmea_r --> da_r : fmea +safety_analysis_r --> da_r : safety_analysis arch_r --> de_r : architectural_design aou_r --> de_r : assumptions_of_use diff --git a/bazel/rules/rules_score/docs/_assets/tooling_chain.puml b/bazel/rules/rules_score/docs/_assets/tooling_chain.puml index 64cbf4a8..88c405db 100644 --- a/bazel/rules/rules_score/docs/_assets/tooling_chain.puml +++ b/bazel/rules/rules_score/docs/_assets/tooling_chain.puml @@ -33,7 +33,7 @@ skinparam rectangle { ' ── Rules (Starlark macros) ─────────────────────────────────────────────────── rectangle "feature_requirements\ncomponent_requirements\nassumed_system_requirements" <> as req rectangle "architectural_design\nunit_design" <> as arch -rectangle "fmea" <> as fmea +rectangle "safety_analysis" <> as safety_analysis rectangle "unit" <> as unit rectangle "dependability_analysis" <> as da rectangle "dependable_element" <> as de @@ -44,7 +44,7 @@ rectangle "**TRLC**\ntrlc parser + trlc_rst\n(.trlc/.rsl -> .rst; TRLCRST lib)" rectangle "**rst_to_trlc**\n(.rst -> .trlc)" <> as r2t rectangle "**PlantUML Parser**\npuml_cli (Rust)\n(.puml -> .fbs.bin + .lobster + .idmap.json)" <> as puml rectangle "**puml_cli** (FTA mode)\ninline metamodel + extract\n(.puml -> inlined .puml +\nfta_chains.json + root_causes.lobster)" <> as fta -rectangle "**fmea_assembler**\nTRLCRST page build\n(.trlc + chains -> fmea.rst)" <> as asm +rectangle "**safety_analysis_assembler**\nTRLCRST page build\n(.trlc + chains -> safety_analysis.rst)" <> as asm rectangle "**Lobster**\nlobster-trlc / -report /\n-ci-report / gtest_report" <> as lob rectangle "**Architecture Verifier**\nvalidation_cli\n(arch.json + .fbs.bin)" <> as verifier rectangle "**Sphinx**\ntoolchain-resolved build binary + private\nhtml_merge tool\n(.rst -> needs.json + HTML)" <> as docs @@ -58,10 +58,10 @@ req --> trlc : render + typecheck req --> lob : lobster-trlc arch --> puml : parse diagrams -fmea --> fta : FTA root causes -fmea --> asm : assemble fmea.rst +safety_analysis --> fta : FTA root causes +safety_analysis --> asm : assemble safety_analysis.rst asm ..> trlc : TRLCRST lib -fmea --> lob : lobster-trlc +safety_analysis --> lob : lobster-trlc unit --> lob : gtest_report da --> lob : lobster-report (FM+CM+FTA) diff --git a/bazel/rules/rules_score/docs/integration_guide.rst b/bazel/rules/rules_score/docs/integration_guide.rst index b7d2604e..c4e37777 100644 --- a/bazel/rules/rules_score/docs/integration_guide.rst +++ b/bazel/rules/rules_score/docs/integration_guide.rst @@ -190,7 +190,7 @@ Complete Example "architectural_design", "assumed_system_requirements", "assumptions_of_use", "component", "component_requirements", "dependability_analysis", "dependable_element", - "feature_requirements", "fmea", "unit") + "feature_requirements", "safety_analysis", "unit") # Requirements assumed_system_requirements(name = "sys_req", srcs = ["docs/sys_req.trlc"]) @@ -208,11 +208,11 @@ Complete Example public_api = ["docs/public_api.puml"]) # Safety analysis - fmea(name = "my_fmea", arch_design = ":arch", + safety_analysis(name = "my_safety_analysis", arch_design = ":arch", controlmeasures = ["docs/controls.trlc"], failuremodes = ["docs/failures.trlc"], root_causes = ["docs/fta.puml"]) - dependability_analysis(name = "analysis", fmea = [":my_fmea"]) + dependability_analysis(name = "analysis", safety_analysis = [":my_safety_analysis"]) # Implementation cc_library(name = "kvs_lib", srcs = ["kvs.cpp"], hdrs = ["kvs.h"]) diff --git a/bazel/rules/rules_score/docs/overview.rst b/bazel/rules/rules_score/docs/overview.rst index 6c702222..67c6a1e5 100644 --- a/bazel/rules/rules_score/docs/overview.rst +++ b/bazel/rules/rules_score/docs/overview.rst @@ -102,7 +102,7 @@ target two layers of checks apply: derivation chain ``AssumedSystemReq → FeatReq → CompReq``, requires an ``Asil`` safety classification and defines the safety-analysis vocabulary (``FailureMode`` with HAZOP ``Guideword``\ s, ``ControlMeasure``, - ``AoU``) used by ``fmea``/``assumptions_of_use``. + ``AoU``) used by ``safety_analysis``/``assumptions_of_use``. Architecture consistency (build) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -311,7 +311,7 @@ Quick Reference * - :ref:`unit_design ` - Artifact - :doc:`user_guide/unit_design` - * - :ref:`fmea ` + * - :ref:`safety_analysis ` - Artifact - :doc:`user_guide/dependability_analysis` * - :ref:`dependability_analysis ` diff --git a/bazel/rules/rules_score/docs/requirements/tool_requirements.trlc b/bazel/rules/rules_score/docs/requirements/tool_requirements.trlc index 0150d03a..122f3c00 100644 --- a/bazel/rules/rules_score/docs/requirements/tool_requirements.trlc +++ b/bazel/rules/rules_score/docs/requirements/tool_requirements.trlc @@ -82,7 +82,7 @@ section "Tool Requirements" { ToolQualification.ToolRequirement Render_All_Failure_Modes { description = ''' - The FMEA rule shall render every FailureMode record from the + The safety_analysis rule shall render every FailureMode record from the input TRLC sources into the documentation output. ''' mitigates = [Missing_Failure_Mode_In_Render] diff --git a/bazel/rules/rules_score/docs/rule_reference.rst b/bazel/rules/rules_score/docs/rule_reference.rst index ff28409a..00dc2b25 100644 --- a/bazel/rules/rules_score/docs/rule_reference.rst +++ b/bazel/rules/rules_score/docs/rule_reference.rst @@ -392,7 +392,7 @@ architectural_design Bundles static, dynamic, public-API, and internal-API architecture views into a single target. Provides ``ArchitecturalDesignInfo`` consumed by ``dependable_element`` -and ``fmea``. +and ``safety_analysis``. .. code-block:: python @@ -487,18 +487,18 @@ implementation. **Generated targets:** ```` (no standalone test; diagrams are consumed by the parent ``unit``) -.. _rule-fmea: +.. _rule-safety-analysis: -fmea -~~~~ +safety_analysis +~~~~~~~~~~~~~~~ -Bundles failure modes, control measures, and FTA diagrams into a single FMEA -documentation target. +Bundles failure modes, control measures, and FTA diagrams into a single +safety-analysis documentation target. .. code-block:: python - fmea( - name = "my_fmea", + safety_analysis( + name = "my_safety_analysis", failuremodes = ["docs/failuremodes.trlc"], controlmeasures = ["docs/controlmeasures.trlc"], root_causes = ["docs/fta.puml"], @@ -545,15 +545,15 @@ documentation target. dependability_analysis ~~~~~~~~~~~~~~~~~~~~~~ -Wraps one or more ``fmea`` targets into a complete safety-analysis package. -Running ``bazel test`` validates the full FMEA traceability chain. +Wraps one or more ``safety_analysis`` targets into a complete safety-analysis package. +Running ``bazel test`` validates the full traceability chain. .. code-block:: python dependability_analysis( - name = "analysis", - arch_design = ":my_arch", - fmea = [":my_fmea"], + name = "analysis", + arch_design = ":my_arch", + safety_analysis = [":my_safety_analysis"], ) .. list-table:: @@ -568,10 +568,10 @@ Running ``bazel test`` validates the full FMEA traceability chain. - string - yes - Target name - * - ``fmea`` + * - ``safety_analysis`` - label list - no - - ``fmea`` targets to include in this analysis (default ``[]``) + - ``safety_analysis`` targets to include in this analysis (default ``[]``) * - ``arch_design`` - label - no @@ -581,7 +581,7 @@ Running ``bazel test`` validates the full FMEA traceability chain. - no - Bazel visibility -**Generated targets:** ```` (build → documentation; ``bazel test //pkg:analysis`` → full FMEA traceability validation) +**Generated targets:** ```` (build → documentation; ``bazel test //pkg:analysis`` → full traceability validation) Structural Rules diff --git a/bazel/rules/rules_score/docs/tooling_architecture.rst b/bazel/rules/rules_score/docs/tooling_architecture.rst index 65debd15..38204a6e 100644 --- a/bazel/rules/rules_score/docs/tooling_architecture.rst +++ b/bazel/rules/rules_score/docs/tooling_architecture.rst @@ -28,7 +28,7 @@ Three layers build wires layers 2 and 3 automatically. #. **Macros / rules** (Starlark, ``private/*.bzl``) — the public work-product - declarations (``feature_requirements``, ``architectural_design``, ``fmea``, + declarations (``feature_requirements``, ``architectural_design``, ``safety_analysis``, ``unit``, ``component``, ``dependability_analysis``, ``dependable_element``, …). Each one declares actions and emits **providers**. #. **Providers** (``providers.bzl``) — the typed contracts that carry data @@ -37,8 +37,8 @@ build wires layers 2 and 3 automatically. :doc:`overview` for the provider-flow diagram. #. **Tools** — the executables each action runs. Some are vendored third-party tools (TRLC, Lobster, the PlantUML parser, Sphinx); some are local helpers - under ``src/`` (``rst_to_trlc.py``, ``fmea_assembler.py``, - ``sphinx_html_merge.py``). The FMEA fault-tree processing lives in the Rust + under ``src/`` (``rst_to_trlc.py``, ``safety_analysis_assembler.py``, + ``sphinx_html_merge.py``). The safety-analysis fault-tree processing lives in the Rust ``puml_cli`` (FTA mode, backed by the ``puml_fta`` crate). Rule → tool invocation map @@ -79,11 +79,11 @@ are rendered under :doc:`tool_reference/index`. - ``@trlc//tools/trlc_rst:trlc_rst`` + TRLC parser; ``trlc_requirements_test`` - ``feature_requirements``, ``component_requirements``, - ``assumed_system_requirements``, ``fmea`` - - Parses and type-checks requirement / FMEA records against the ``.rsl`` + ``assumed_system_requirements``, ``safety_analysis`` + - Parses and type-checks requirement / safety-analysis records against the ``.rsl`` metamodel and renders them to ``.rst``. ``trlc_rst`` also ships a - reusable ``TRLCRST`` library that ``fmea_assembler`` links directly to - build the FMEA page from a single in-process parse (no per-record + reusable ``TRLCRST`` library that ``safety_analysis_assembler`` links directly to + build the safety-analysis page from a single in-process parse (no per-record ``.inc`` files). * - **rst_to_trlc** - ``src/rst_to_trlc.py`` (local) @@ -102,7 +102,7 @@ are rendered under :doc:`tool_reference/index`. * - **puml_cli (FTA mode)** - ``//plantuml/parser/puml_cli`` ``--fta-output-dir`` (Rust; FTA model in the ``puml_fta`` crate) - - ``fmea`` + - ``safety_analysis`` - Analysis only: parses the ``$TopEvent`` / ``$BasicEvent`` / gate macro calls of each root-cause FTA diagram into two outputs: ``root_causes.lobster`` (``lobster-act-trace``) and @@ -113,20 +113,11 @@ are rendered under :doc:`tool_reference/index`. sphinxcontrib-plantuml's ``-pipe`` mode. Unrooted basic events and malformed TRLC aliases are reported as build warnings rather than silently dropped. - * - **fmea_assembler** - - ``//bazel/rules/rules_score:fmea_assembler`` - (``src/fmea_assembler.py``, local; links the ``TRLCRST`` library) - - ``fmea`` - - Assembles the failure-mode-centric ``fmea.rst`` from ``fta_chains.json`` - plus the FailureMode / ControlMeasure records in one in-process TRLC - parse: an overview table, one section per failure mode (detail + inline - fault tree + that chain's control measures), and trailing "Unlinked" - sections so nothing is dropped. - * - **safety_analysis_tools** - - ``//bazel/rules/rules_score:safety_analysis_tools`` - (``src/safety_analysis_tools.py``, local) - - ``fmea`` - - Assembles the failure-mode-centric ``fmea.rst`` from ``fta_chains.json`` + * - **safety_analysis_assembler** + - ``//bazel/rules/rules_score:safety_analysis_assembler`` + (``src/safety_analysis_assembler.py``, local; links the ``TRLCRST`` library) + - ``safety_analysis`` + - Assembles the failure-mode-centric ``safety_analysis.rst`` from ``fta_chains.json`` plus the FailureMode / ControlMeasure records in one in-process TRLC parse: an overview table, one section per failure mode (detail + inline fault tree + that chain's control measures), and trailing "Unlinked" @@ -135,7 +126,7 @@ are rendered under :doc:`tool_reference/index`. - ``@lobster//`` : ``lobster-trlc``, ``lobster-report``, ``lobster-ci-report``, ``lobster-html-report``, ``gtest_report``, ``lobster-rst-report`` - - ``*_requirements``, ``fmea``, ``unit``, ``dependability_analysis``, + - ``*_requirements``, ``safety_analysis``, ``unit``, ``dependability_analysis``, ``dependable_element`` - The traceability backbone. ``lobster-trlc`` extracts ``.lobster`` items from TRLC; ``gtest_report`` turns test results into ``.lobster``; @@ -205,7 +196,7 @@ feed that pipeline: * **Requirements** (``.trlc``) → ``lobster-trlc`` → ``requirements.lobster``. * **Public API diagrams** (``public_api.puml``) → PlantUML parser → ``public_api.lobster`` (enables failure-mode-to-interface tracing). -* **FMEA** (``failuremodes.trlc`` / ``controlmeasures.trlc``) → ``lobster-trlc``; +* **Safety analysis** (``failuremodes.trlc`` / ``controlmeasures.trlc``) → ``lobster-trlc``; **FTA** (``fta.puml``) → ``puml_cli`` (FTA mode) → ``root_causes.lobster``. * **Unit tests** (gtest) → ``gtest_report`` → ``.lobster``. @@ -326,11 +317,11 @@ self-contained. Safety analysis document pipeline ---------------------------------- -The component diagram below shows how the FMEA **input artifacts** — authored +The component diagram below shows how the safety-analysis **input artifacts** — authored ``.trlc`` records and ``fta_*.puml`` diagrams plus the tooling defaults -(``ScoreReq`` ``.rsl`` spec, ``fta_metamodel.puml``, ``fmea.template.rst`` and +(``ScoreReq`` ``.rsl`` spec, ``fta_metamodel.puml``, ``safety_analysis.template.rst`` and the lobster configs) — flow through the three in-process tool actions of the -``fmea`` rule into the generated files, the providers, and finally the Sphinx +``safety_analysis`` rule into the generated files, the providers, and finally the Sphinx staging tree. Blue boxes are authored sources, light-blue are tooling defaults, green components are the tool actions, orange boxes are generated files, yellow boxes are the provider payloads, and the purple box is the staging directory @@ -341,17 +332,17 @@ consumed by Sphinx. :alt: Safety analysis document pipeline :width: 100% -The ``fmea`` rule drives three actions, all reading the input artifacts above: +The ``safety_analysis`` rule drives three actions, all reading the input artifacts above: #. **puml_cli (FTA mode)** parses each ``fta_*.puml`` directly (no rewriting) and writes ``root_causes.lobster`` and ``fta_chains.json`` (the ordered per-failure-mode chains). The diagrams keep their ``!include fta_metamodel.puml``; the metamodel is on PlantUML's global include path (shipped in the docs toolchain runfiles), so it resolves at render time. -#. **fmea_assembler** consumes ``fta_chains.json`` and parses the FailureMode / +#. **safety_analysis_assembler** consumes ``fta_chains.json`` and parses the FailureMode / ControlMeasure ``.trlc`` records (with the ``.rsl`` spec for import resolution) in a single in-process ``TRLCRST`` pass, expanding - ``fmea.template.rst`` into ``fmea.rst``. + ``safety_analysis.template.rst`` into ``safety_analysis.rst``. #. **lobster-trlc** (run twice) turns the FailureMode and ControlMeasure records into ``failuremodes.lobster`` / ``controlmeasures.lobster`` for the traceability report. @@ -359,14 +350,14 @@ The ``fmea`` rule drives three actions, all reading the input artifacts above: ``SphinxSourcesInfo`` carries three depsets: - **srcs** — files that become top-level toctree entries in the enclosing - document section. ``fmea`` emits exactly one: ``fmea.rst``. + document section. ``safety_analysis`` emits exactly one: ``safety_analysis.rst``. - **deps** — all files that must be present in the staging directory; for - ``fmea`` this is just ``fmea.rst``, because the page is self-contained + ``safety_analysis`` this is just ``safety_analysis.rst``, because the page is self-contained (failure modes and control measures are rendered inline, not pulled in via ``.. include::``). - **aux_srcs** — files to symlink alongside ``srcs``/``deps`` but **not** added - to any toctree. ``fmea`` uses this for the authored ``fta_*.puml`` diagrams, - which ``fmea.rst`` references inline via ``.. uml::`` and which must therefore + to any toctree. ``safety_analysis`` uses this for the authored ``fta_*.puml`` diagrams, + which ``safety_analysis.rst`` references inline via ``.. uml::`` and which must therefore sit beside it in the staging tree without being indexed as documents. (The metamodel is not staged here — it resolves via PlantUML's global include path.) diff --git a/bazel/rules/rules_score/docs/user_guide/architectural_design.rst b/bazel/rules/rules_score/docs/user_guide/architectural_design.rst index 3729dc3c..21bc31a9 100644 --- a/bazel/rules/rules_score/docs/user_guide/architectural_design.rst +++ b/bazel/rules/rules_score/docs/user_guide/architectural_design.rst @@ -147,77 +147,6 @@ Common anti-patterns - **Leaky public API** — exposing an interface publicly for convenience. It then drags in unnecessary failure modes and AoUs. -Rendering: Diagrams, Wrapper Pages, and Directory Navigation ---------------------------------------------------------------- - -Each view (``static``, ``dynamic``, ``public_api``, ``internal_api``) is just a -flat list of ``.puml``/``.plantuml`` files, but Sphinx needs an actual page to -put every diagram on, plus a place in the sidebar to reach it from. -``architectural_design`` builds that structure automatically: - -- Every diagram gets an auto-generated wrapper page — a ``.rst`` file - containing a single ``.. uml::`` directive — named after the diagram's own - file stem (``foo.puml`` → page ``foo``). -- Every directory that contains at least one diagram or authored page gets a - generated ``index.rst`` with a ``toctree`` listing that directory's pages - and its subdirectories, mirroring the on-disk layout of the files you passed - to ``static``/``dynamic``/``public_api``/``internal_api``. Nesting is - unlimited. -- Directory levels that hold nothing of their own and lead to a single - subdirectory are skipped, so a diagram at ``foo/bar/baz.puml`` is reached - through one ``foo/bar/index.rst`` rather than a chain of navigation pages - that each contain a single link. A view consisting of one page and nothing - else gets no generated index at all; that page becomes the view's root. -- The view's top-level (root) index is the single toctree entry surfaced on - the enclosing ``dependable_element`` page for that view. - -Authoring pages alongside diagrams -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A generated wrapper page is only a placeholder; real prose belongs alongside -your ``.puml`` files, passed in the same view attribute. What happens depends -on the file's stem relative to the diagrams already in that directory: - -.. list-table:: - :header-rows: 1 - - * - You add - - Effect - - When to use it - * - ``.rst``/``.md`` with no matching ``.puml`` in the same - directory - - **Standalone page** — an ordinary extra entry in that directory's - toctree. - - Prose that isn't about one specific diagram — design rationale, an - overview, background context. - * - ``.rst``/``.md`` next to a same-stem ``.puml``/ - ``.plantuml`` - - **Override** — replaces that diagram's generated wrapper page - outright. The ``.puml`` is still staged as a sibling, so your page can - embed it with its own ``.. uml:: .puml``. - - You want narrative directly around one specific diagram instead of it - rendering bare. - * - ``index.rst``/``index.md`` - - **Compose** — your content is rendered *above* the generated - directory-level toctree, which is otherwise left untouched (every - diagram in that directory keeps its navigation entry). Your title - becomes the index page's title. - - A directory-level introduction that must not hide any diagram from - the navigation. - -A ``.puml``/``.plantuml`` file whose own stem is literally ``index`` is -rejected at analysis time — that stem is reserved for the directory's -generated navigation page; name the diagram something else. - -Two files that would stage at the same relative path (for example both a -``.rst`` and a ``.md`` for the same stem) also fail the build, with a message -naming both conflicting sources, instead of surfacing a raw Bazel -action-conflict error. - -See ``examples/seooc/design`` for a working demonstration: ``index.md`` -composes an introduction above the static view's root navigation, and -``public_api.rst`` overrides the generated wrapper for ``public_api.puml``. - Static Architecture -------------------- @@ -439,7 +368,7 @@ Bazel public_api = ["public_api.puml"], ) -The ``public_api`` attribute also generates traceability items that can be referenced by ``fmea`` targets (see :doc:`dependability_analysis`) via the ``arch_design`` attribute. +The ``public_api`` attribute also generates traceability items that can be referenced by ``safety_analysis`` targets (see :doc:`dependability_analysis`) via the ``arch_design`` attribute. Internal API -------------- diff --git a/bazel/rules/rules_score/docs/user_guide/dependability_analysis.rst b/bazel/rules/rules_score/docs/user_guide/dependability_analysis.rst index 00b1b020..b88860cc 100644 --- a/bazel/rules/rules_score/docs/user_guide/dependability_analysis.rst +++ b/bazel/rules/rules_score/docs/user_guide/dependability_analysis.rst @@ -12,11 +12,11 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* -Dependability Analysis -======================= +Safety Analysis +=============== .. note:: - A complete working example covering ``fmea`` and ``dependability_analysis`` is + A complete working example covering ``safety_analysis`` and ``dependability_analysis`` is available in `bazel/rules/rules_score/examples/seooc/safety_analysis/ `_. @@ -30,25 +30,40 @@ Overview Why safety analysis? ~~~~~~~~~~~~~~~~~~~~~ -Safety analysis is required to systematically identify failures that could -violate safety goals and to demonstrate that appropriate countermeasures are -in place. In ISO 26262 terms it provides the evidence that residual risk is -acceptable. +A safety analysis shall support the process to systematically identify failures which could +violate safety goals or safety requirements. It shall also help to identify their root causes and design +appropriate countermeasures. -How FMEA works -~~~~~~~~~~~~~~~ +Safety analyses are typically performed with two complementary methods: -A Failure Mode and Effects Analysis (FMEA) follows three steps for each public -interface of the software module: +- **FMEA (Failure Mode and Effects Analysis)** is an inductive, bottom-up method: + it examines individual components mainly at their interfaces, how they can fail, and what effect those failures have on the overall system. +- **FTA (Fault Tree Analysis)** is a deductive, top-down method: + depending on the context it starts from a safety goal / safety requirement / failure (mode) and traces back to the potential causes that could lead to it. -1. **Identify failure modes** — apply structured fault models (see below) to - each public interface to derive what can cause a violation of a - overarching safety goal. -2. **Analyse effects and causes** — document the effect on the system and - decompose to root causes using a Fault Tree Analysis (FTA). +How safety analyses are used in this context +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +SEooCs are designed to be included in a system (e.g. platform). This means that from a system point +of view the SEooCs are the leaves of its FMEA. Thus failure modes of the SEooC can be +identified by applying the FMEA methodology (structured fault models) to its interface (aka public API). + +In a second step the root causes of the identified failure modes need to be analyzed within the SEooC. This can be achieved by performing a Fault Tree Analysis (FTA). Each identified root cause then needs to be treated with appropriate safety measures to guarantee that a safety-related failure mode cannot occur in the first place. + +So the single steps are: + +1. **Identify failure modes** — apply structured fault models (see + `Fault models`_) to each public interface to derive what can cause a + violation of an overarching safety goal. +2. **Analyze effects and causes** — decompose the identified failure modes + into their root causes using a Fault Tree Analysis (FTA). 3. **Define countermeasures** — for every root cause specify a - ``ControlMeasure`` (or ``PreventiveMeasure`` / ``Mitigation``) and trace it - back through the FTA to the failure mode. + ``ControlMeasure`` (or ``PreventiveMeasure`` / ``Mitigation`` / ``AoU``) and + trace it back through the FTA to the failure mode. +4. **Wire and validate** — bundle the resulting artifacts in Bazel and let the + traceability check verify that they are consistently linked. + +Each step is described in detail in `Performing the Analysis`_. Fault models ~~~~~~~~~~~~~ @@ -63,29 +78,70 @@ loss, delay, corruption, non-determinism). The ``Guideword`` enum in the ``ScoreReq`` model maps each category to a structured label used in the ``FailureMode`` records. -The description below covers the FMEA-based **safety** analysis for a -software module. +Artifacts and traceability +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As mentioned above, the safety analysis method used by ``dependability_analysis`` is a combination of both an FMEA and a FTA. +Each ``safety_analysis`` target bundles four types of artifacts that must be linked together: + +.. list-table:: + :header-rows: 1 + + * - Artifact + - Format + - What it represents + - Created in + * - **Public API Interfaces** + - PlantUML (from ``architectural_design.public_api``) + - Interfaces where failures can manifest; referenced by ``FailureMode.interface`` + - :doc:`architectural_design` + * - **Failure Modes** + - TRLC (``.trlc``) + - Effects identified in the FMEA: what can go wrong and its impact + - Step 1 + * - **FTA Diagrams** + - PlantUML (``.puml``) + - Fault Tree Analysis: structural decomposition of each failure mode into root causes + - Step 2 + * - **Control Measures** + - TRLC (``.trlc``) + - Countermeasures that address the root causes identified in the FTA + - Step 3 + +The artifacts are linked purely by naming conventions — no separate linking +step is needed: + +- ``FailureMode.interface`` references an element of the ``public_api`` of the + ``architectural_design`` target. This connects the architectural view to the + safety analysis. +- The **alias** of a ``$TopEvent`` in an FTA diagram is the **TRLC + fully-qualified record name** (``Package.RecordName``) of the + ``FailureMode`` it decomposes. +- The **alias** of a ``$BasicEvent`` in an FTA diagram is the TRLC + fully-qualified record name of the measure that addresses this root cause. + +The traceability check verifies these links automatically (see +`Traceability Validation`_). Performing the Analysis ----------------------- The Bazel rule and traceability check only verify that the artifacts are -*linked* — they cannot tell you whether the analysis is *complete or correct*. +*linked* and *traced* — they cannot tell you whether the analysis is *complete or correct*. Identifying failure modes, reasoning about causes, and choosing countermeasures -is a safety-engineering activity governed by the S-CORE -`Safety Analysis process area `_ -and its -`FMEA fault models guideline `_. -Work through it in this order. +is a safety-engineering activity. + +The following steps walk through this activity. Each step first explains the +safety reasoning and then shows how its result is recorded as an artifact. All +snippets are taken from the SEooC example in +``bazel/rules/rules_score/examples/seooc``. Step 1 — Identify failure modes per interface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Go through the ``public_api`` **method by method**. For each method, walk the applicable fault models and ask *"can this occur, and would it violate a safety -goal?"* Record only the plausible, safety-relevant ones — the guideline marks -many models as *low relevance* (e.g. "message received too early") that you can -dismiss with a short rationale. +goal or safety requirement?"* The ``Guideword`` enum labels the fault-model category on each ``FailureMode``: @@ -97,132 +153,21 @@ The ``Guideword`` enum labels the fault-model category on each ``FailureMode``: - Example fault models - ``Guideword`` labels * - **Message** (send/receive) - - not sent / not received, corrupted, lost, unintended (``MF_01_*``) + - not sent / not received, corrupted, lost, unintended - ``LossOfFunction``, ``PartialFunction``, ``Corrupted``, ``UnintendedFunction``, ``Wrong`` * - **Timing / duration constraint** - - too late / too early, boundary violated (``CO_01_*``) + - too late / too early, boundary violated - ``TooEarly``, ``TooLate``, ``DelayedFunction`` * - **Execution** - - wrong result, loss of execution, arbitrary/incomplete (``EX_01_*``) + - wrong result, loss of execution, arbitrary/incomplete - ``Wrong``, ``LossOfFunction``, ``ExceedingFunction``, ``ArbitraryExecution`` -**Clustering:** create **one** ``FailureMode`` record per *(interface, guideword)* -effect, not one per method blindly. If the same root cause produces the same -effect across several methods, list them together in the ``interface`` field. A -single root cause that manifests under two guide words needs two records (TRLC -allows one ``guidewords`` classification per record). - -Step 2 — Analyse the effect, then decompose to causes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- **Effect** (``failureeffect``) — describe the consequence **from the caller / - system perspective**, in worst-case terms, relative to the safety goal. "Returns - a stale value that the controller uses to actuate" is a usable effect; "function - returns wrong data" is not. -- **Causes** — build the Fault Tree (FTA) top-down from the failure mode to its - **root causes**: - - - Use an **OR gate** when *any single* child cause is sufficient to produce the - parent — this is the default for independent causes. - - Use an **AND gate** only when *all* children must occur together (e.g. a fault - plus the failure of a safety mechanism) — this is what justifies a lower - residual risk. - - Decompose until each leaf (``$BasicEvent``) is an **actionable root cause** you - can place a measure on — not a vague restatement of the failure. - -Step 3 — Choose a countermeasure for every root cause -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Every ``$BasicEvent`` needs exactly one measure record. Pick the type by *when* it -acts: - -.. list-table:: - :header-rows: 1 - :widths: 24 46 30 - - * - Type - - Use when the measure… - - Acts - * - ``PreventiveMeasure`` - - removes the cause so the fault cannot occur. - - before - * - ``ControlMeasure`` - - detects and handles the fault at runtime (plausibility check, monitor). - - during - * - ``Mitigation`` - - reduces severity/probability after the fault has occurred. - - after - * - ``AoU`` (Assumption of Use) - - can only be guaranteed by the **integrator/caller**, not inside the SEooC. - - at integration - -An ``AoU`` is how you *push an obligation outward* when the SEooC cannot close a -root cause itself — it must be forwarded to the integrating project (see -:doc:`assumptions_of_use`). - -**ASIL rationale:** the ``safety`` level on a ``FailureMode`` follows the safety -goal it can violate; a ``ControlMeasure`` that an ASIL argument relies on inherits -that level. Record *why* a measure is sufficient — an AND-gate decomposition or a -diagnostic coverage claim — rather than only *that* it exists. - -Bazel Rule ``dependability_analysis`` ----------------------------------------- - -.. code-block:: starlark - - load("@score_tooling//bazel/rules/rules_score:rules_score.bzl", - "dependability_analysis") - - dependability_analysis( - name = "my_da", - arch_design = ":my_arch", - fmea = [":my_fmea"], - ) - -**Generated targets:** ```` — build produces the documentation and -traceability report; ``bazel test`` validates the full chain. - -FMEA ----- - -The Failure Mode and Effects Analysis (FMEA) is the core safety analysis -method used by ``dependability_analysis``. Each ``fmea`` target bundles four -types of artifacts that must be linked together: - -.. list-table:: - :header-rows: 1 - - * - Artifact - - Format - - What it represents - * - **Public API Interfaces** - - PlantUML (from ``architectural_design.public_api``) - - Interfaces where failures can manifest; referenced by ``FailureMode.interface`` - * - **Failure Modes** - - TRLC (``.trlc``) - - Effects identified in the FMEA: what can go wrong and its impact - * - **FTA Diagrams** - - PlantUML (``.puml``) - - Fault Tree Analysis: structural decomposition of each failure mode into root causes - * - **Control Measures** - - TRLC (``.trlc``) - - Countermeasures that address the root causes identified in the FTA - -The public API connects the architectural view to the safety analysis: -``FailureMode.interface`` references an interface name defined in the -``public_api`` of the ``architectural_design`` target. - -The FTA artifacts are linked by a shared naming convention: the **TRLC -fully-qualified record name** (package + record name) must match the -**alias** used in the FTA PlantUML diagram. This is how traceability is -established automatically in the report. +Recording failure modes (TRLC) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Failure Modes (TRLC) -~~~~~~~~~~~~~~~~~~~~~ - -A failure mode is a ``FailureMode`` record in the ``ScoreReq`` model. The -example below is taken from ``examples/seooc/safety_analysis``: +Each identified failure mode is recorded as a ``ScoreReq.FailureMode`` record +in a ``.trlc`` file (here ``sample_safety_analysis_failure_modes.trlc``): .. code-block:: text @@ -236,72 +181,114 @@ example below is taken from ``examples/seooc/safety_analysis``: failureeffect = "The world as we know it will end" version = 1 safety = ScoreReq.Asil.B - interface = "SampleLibraryAPI.GetNumber" + interface = "safety_software_seooc_example.SampleLibraryAPI.GetNumber" } -The TRLC fully-qualified name of this record is -**``SampleLibrary.SampleFailureMode``**. This name is used as the -``$TopEvent`` alias in the FTA diagram. - -FTA Diagrams (PlantUML) -~~~~~~~~~~~~~~~~~~~~~~~~ +.. list-table:: + :header-rows: 1 + :widths: 25 75 + + * - Attribute + - Meaning + * - ``guidewords`` + - One or more ``Guideword`` values classifying the failure (see table above). + * - ``description`` + - What goes wrong. + * - ``failureeffect`` + - Consequence for the caller / system (see Step 2). + * - ``interface`` + - Fully-qualified name of the affected ``public_api`` element + (``..``). Links the failure mode to the + architecture. + * - ``safety`` + - ASIL of the safety goal the failure mode can violate (see *ASIL + rationale* in Step 3). + * - ``version`` + - Monotonically increasing counter; increment on every content change. + * - ``rationale`` (optional) + - Why this failure mode is considered relevant. + +The record's fully-qualified name, ``SampleLibrary.SampleFailureMode`` +(package + record name), becomes the ``$TopEvent`` alias of its fault tree in +Step 2. + +Step 2 — Analyze the effect, then decompose to root causes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- **Effect** — describe the consequence **from the caller / system + perspective**, in worst-case terms, relative to the safety goal. It is + recorded in the ``failureeffect`` attribute of the ``FailureMode``. +- **Causes** — build a Fault Tree (FTA) top-down from the failure mode to its + **root causes**: -Each failure mode gets a Fault Tree Analysis diagram. A dedicated PlantUML -metamodel -(`fta_metamodel.puml `_) -provides the graphical elements — it is located at -``plantuml/fta_metamodel.puml`` in the score-tooling repository. Your diagram -uses procedure calls from that metamodel; no standard PlantUML shapes are -needed. + - Use an **OR gate** when *any single* child cause is sufficient to produce the + parent — this is the default for independent causes. + - Use an **AND gate** only when *all* children must occur together (e.g. a fault + plus the failure of a safety mechanism) — this is what justifies a lower + residual risk. + - Decompose until each leaf (``$BasicEvent``) is an **actionable root cause** you + can place a measure on — not a vague restatement of the failure. -Every ``.puml`` FTA file must begin with ``!include fta_metamodel.puml`` so -that the procedure definitions are available. +Modeling the fault tree (PlantUML) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Available procedures -^^^^^^^^^^^^^^^^^^^^^ +Each failure mode gets its own FTA diagram. A dedicated PlantUML metamodel +(`fta_metamodel.puml `_, +located at ``plantuml/fta_metamodel.puml`` in the score-tooling repository) +provides the graphical elements as procedures; no standard PlantUML shapes are +needed. Every FTA ``.puml`` file must begin with ``!include fta_metamodel.puml`` +so that the procedure definitions are available. .. list-table:: :header-rows: 1 + :widths: 35 65 * - Procedure - Description * - ``$TopEvent(name, alias)`` - - The top-level failure mode. ``alias`` must equal the fully-qualified TRLC name of the corresponding ``FailureMode`` record (e.g. ``SampleLibrary.SampleFailureMode``) + - The failure mode at the root of the tree. ``alias`` must equal the + fully-qualified TRLC name of the corresponding ``FailureMode`` record + (e.g. ``SampleLibrary.SampleFailureMode``). * - ``$IntermediateEvent(name, alias, connection)`` - - An intermediate cause. ``connection`` is the **alias of the parent** node this event feeds into + - An intermediate cause that is decomposed further. ``connection`` is the + alias of the parent node this event feeds into. * - ``$BasicEvent(name, alias, connection)`` - - A root cause (leaf node). ``alias`` must equal the fully-qualified TRLC name of the corresponding ``ControlMeasure`` record. ``connection`` is the alias of the parent gate + - A root cause (leaf node). ``alias`` must equal the fully-qualified TRLC + name of the measure record that addresses it (Step 3). ``connection`` is + the alias of the parent gate. * - ``$AndGate(alias, connection)`` - - AND gate. All children must occur for the parent to trigger. ``connection`` is the alias of the parent node + - AND gate: all children must occur for the parent to occur. + ``connection`` is the alias of the parent node. * - ``$OrGate(alias, connection)`` - - OR gate. Any single child is sufficient to trigger the parent. ``connection`` is the alias of the parent node - * - ``$TransferInGate(name, alias, connection)`` - - Transfer-in gate linking to another FTA sub-tree - -Linking procedures together -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + - OR gate: any single child is sufficient for the parent to occur. + ``connection`` is the alias of the parent node. + * - ``$TransferInGate(alias, connection)`` + - Transfer-in gate linking to another FTA sub-tree. ``alias`` is the + fully-qualified TRLC name of that sub-tree's ``$TopEvent``; + ``connection`` is the alias of the parent node. Each element points to its **parent** via the ``connection`` parameter — the -arrow goes *from* the element *up* to the parent. Build the tree bottom-up: +arrow goes *from* the element *up* to the parent. Declare the tree from the top +down: 1. Declare the ``$TopEvent`` first (no ``connection`` parameter — it is the root). -2. Declare gate(s) with ``connection`` set to the ``$TopEvent`` alias. -3. Declare ``$BasicEvent`` / ``$IntermediateEvent`` nodes with ``connection`` - set to the enclosing gate's alias. +2. Declare the gate(s) with ``connection`` set to the ``$TopEvent`` alias. +3. Declare ``$IntermediateEvent`` / ``$BasicEvent`` nodes with ``connection`` + set to the enclosing gate's alias. An ``$IntermediateEvent`` is decomposed + further by gates whose ``connection`` is its alias. :: - $TopEvent ← root, no connection - └── $OrGate(alias="OG_1", connection="TopEvent.alias") - ├── $BasicEvent(alias="CM_A", connection="OG_1") - └── $BasicEvent(alias="CM_B", connection="OG_1") + $TopEvent(alias="Pkg.FailureMode") ← root, no connection + └── $OrGate(alias="OG1", connection="Pkg.FailureMode") + ├── $BasicEvent(alias="Pkg.MeasureA", connection="OG1") + └── $BasicEvent(alias="Pkg.MeasureB", connection="OG1") -The ``$BasicEvent`` **alias IS the fully-qualified TRLC name** -(``Package.RecordName``) of the corresponding ``ControlMeasure`` record. No -separate linking step is needed — the naming convention is the link. +Gate and intermediate-event aliases (e.g. ``OG1``) are only local identifiers +within the diagram; they do not refer to TRLC records. -Example FTA diagram -^^^^^^^^^^^^^^^^^^^^ +For example, the fault tree for ``SampleLibrary.SampleFailureMode`` (the +``FailureMode`` from Step 1) decomposes as follows: .. uml:: ../_assets/SeoocExample_FTA.puml :align: center @@ -325,11 +312,46 @@ Example FTA diagram @enduml -Control Measures (TRLC) -~~~~~~~~~~~~~~~~~~~~~~~~ +``SampleLibrary.JustBadLuck`` alone is sufficient to cause the failure mode (OR +gate), whereas ``SampleLibrary.NoMoreCookies`` and +``SampleLibrary.NoMoreCoffee`` must occur together (AND gate) to cause the +intermediate event. Each of these basic events needs a measure in Step 3. -For each ``$BasicEvent`` in your FTA diagram, define a ``ControlMeasure`` -record whose fully-qualified name matches the event alias: +Step 3 — Choose a countermeasure for every root cause +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Every ``$BasicEvent`` needs exactly one measure record. Pick the type by *when* it +acts: + +.. list-table:: + :header-rows: 1 + :widths: 24 46 30 + + * - Type + - Use when the measure… + - Acts + * - ``PreventiveMeasure`` + - removes the cause so the fault cannot occur. + - before + * - ``ControlMeasure`` + - detects and handles the fault at runtime (plausibility check, monitor). + - during + * - ``Mitigation`` + - reduces severity/probability after the fault has occurred. + - after + * - ``AoU`` (Assumption of Use) + - can only be guaranteed by the **integrator/caller**, not inside the SEooC. + - at integration + +Recording measures (TRLC) +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Each measure is a TRLC record whose fully-qualified name (package + record +name) equals the alias of the ``$BasicEvent`` it addresses. For example, the +following ``ControlMeasure`` records (from +``sample_safety_analysis_control_measures.trlc``) address the ``JustBadLuck``, +``NoMoreCookies``, and ``NoMoreCoffee`` basic events from the FTA diagram in +Step 2: .. code-block:: text @@ -355,69 +377,35 @@ record whose fully-qualified name matches the event alias: version = 1 } -The alias ``SampleLibrary.JustBadLuck`` in the FTA diagram matches the TRLC -record ``JustBadLuck`` in package ``SampleLibrary`` — and likewise for -``NoMoreCookies``/``NoMoreCoffee``. This is how the traceability link is -established. - -Other measure types -^^^^^^^^^^^^^^^^^^^^ - -The SCORE requirements model also defines ``PreventiveMeasure`` and -``Mitigation``, both extending the same abstract ``Measure`` base type as -``ControlMeasure``. Their Bazel and TRLC usage follows the same pattern; the -record type name changes but the FTA alias convention (package + record name -matching the ``$BasicEvent`` alias) is identical. - -``fmea`` — Bazel Rule -~~~~~~~~~~~~~~~~~~~~~~ +The ``ScoreReq`` model also defines ``PreventiveMeasure`` and ``Mitigation`` +record types. The record type name changes, but the FTA alias convention +(package + record name matching the ``$BasicEvent`` alias) is identical. -For the complete ``fmea`` attribute reference, see :ref:`fmea ` in -the rule index. - -Traceability Validation ------------------------- - -Running ``bazel test //my/package:my_da`` executes a traceability check that -validates the complete chain: - -:: - - public_api interface ← FailureMode.interface - | - $TopEvent - | - AND / OR gate(s) - | - $BasicEvent - | - ControlMeasure - -The check fails if: - -- A ``$TopEvent`` alias does not match any ``FailureMode`` record name -- A ``$BasicEvent`` alias does not match any ``ControlMeasure`` record name -- A ``FailureMode`` or ``ControlMeasure`` is defined but not referenced in any FTA diagram +An ``AoU`` is how you *push an obligation outward* when the SEooC cannot close a +root cause itself — it must be forwarded to the integrating project (see +:doc:`assumptions_of_use`). -Fixing a traceability error means ensuring the naming convention is followed -precisely: the fully-qualified TRLC name (package + record name, e.g. -``SampleLibrary.JustBadLuck``) must be used verbatim as the alias in the FTA diagram. +**ASIL rationale:** the ``safety`` level on a ``FailureMode`` follows the safety +goal it can violate; a ``ControlMeasure`` that an ASIL argument relies on inherits +that level. Record *why* a measure is sufficient — an AND-gate decomposition or a +diagnostic coverage claim — rather than only *that* it exists. -Example -------- +Step 4 — Wire the analysis into Bazel +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``fmea`` rule's ``failuremodes``/``controlmeasures``/``root_causes`` -files must live in the **same package** as the ``fmea`` target itself (Bazel -does not allow referencing another package's raw source files without -``exports_files``). The parent ``dependability_analysis`` target then -references the ``fmea`` target by label: +The artifacts from Steps 1–3 are bundled in a ``safety_analysis`` target. Its +``failuremodes``, ``controlmeasures`` and ``root_causes`` files must live in the +**same package** as the ``safety_analysis`` target itself (Bazel does not allow +referencing another package's raw source files without ``exports_files``). +``arch_design`` points to the ``architectural_design`` target whose +``public_api`` is referenced by ``FailureMode.interface``: .. code-block:: starlark :caption: bazel/rules/rules_score/examples/seooc/safety_analysis/BUILD load( "@score_tooling//bazel/rules/rules_score:rules_score.bzl", - "fmea", + "safety_analysis", ) filegroup( @@ -429,15 +417,18 @@ references the ``fmea`` target by label: visibility = ["//visibility:public"], ) - fmea( - name = "sample_fmea", + safety_analysis( + name = "sample_safety_analysis", arch_design = "//design:sample_seooc_design", - controlmeasures = ["sample_fmea_control_measures.trlc"], - failuremodes = ["sample_fmea_failure_modes.trlc"], + controlmeasures = ["sample_safety_analysis_control_measures.trlc"], + failuremodes = ["sample_safety_analysis_failure_modes.trlc"], root_causes = [":sample_fta"], visibility = ["//visibility:public"], ) +The ``dependability_analysis`` target of the dependable element then +references one or more ``safety_analysis`` targets by label: + .. code-block:: starlark :caption: bazel/rules/rules_score/examples/seooc/BUILD @@ -447,7 +438,44 @@ references the ``fmea`` target by label: ) dependability_analysis( - name = "sample_dependability_analysis", + name = "sample_dependability_analysis", arch_design = "//design:sample_seooc_design", - fmea = ["//safety_analysis:sample_fmea"], + safety_analysis = ["//safety_analysis:sample_safety_analysis"], ) + +**Generated targets:** ```` — ``bazel build`` produces the documentation +and traceability report; ``bazel test`` validates the full chain (see +`Traceability Validation`_). + +For the complete attribute reference, see +:ref:`safety_analysis ` and +:ref:`dependability_analysis ` in the rule index. + +Traceability Validation +------------------------ + +Running ``bazel test`` on the ``dependability_analysis`` target (e.g. +``bazel test //:sample_dependability_analysis`` in the SEooC example) executes +a traceability check that validates the complete chain: + +:: + + public_api interface ← FailureMode.interface + | + $TopEvent + | + AND / OR gate(s) + | + $BasicEvent + | + ControlMeasure + +The check fails if: + +- A ``$TopEvent`` alias does not match any ``FailureMode`` record name +- A ``$BasicEvent`` alias does not match any ``ControlMeasure`` record name +- A ``FailureMode`` or ``ControlMeasure`` is defined but not referenced in any FTA diagram + +Fixing a traceability error means ensuring the naming convention is followed +precisely: the fully-qualified TRLC name (package + record name, e.g. +``SampleLibrary.JustBadLuck``) must be used verbatim as the alias in the FTA diagram. diff --git a/bazel/rules/rules_score/examples/seooc/BUILD b/bazel/rules/rules_score/examples/seooc/BUILD index de798362..06ea6d14 100644 --- a/bazel/rules/rules_score/examples/seooc/BUILD +++ b/bazel/rules/rules_score/examples/seooc/BUILD @@ -67,7 +67,7 @@ component( dependability_analysis( name = "sample_dependability_analysis", arch_design = "//design:sample_seooc_design", - fmea = ["//safety_analysis:sample_fmea"], + safety_analysis = ["//safety_analysis:sample_safety_analysis"], ) dependable_element( diff --git a/bazel/rules/rules_score/examples/seooc/safety_analysis/BUILD b/bazel/rules/rules_score/examples/seooc/safety_analysis/BUILD index cfba949a..6f7362ac 100644 --- a/bazel/rules/rules_score/examples/seooc/safety_analysis/BUILD +++ b/bazel/rules/rules_score/examples/seooc/safety_analysis/BUILD @@ -13,7 +13,7 @@ load( "@score_tooling//bazel/rules/rules_score:rules_score.bzl", - "fmea", + "safety_analysis", ) # FTA @@ -27,11 +27,11 @@ filegroup( visibility = ["//visibility:public"], ) -fmea( - name = "sample_fmea", +safety_analysis( + name = "sample_safety_analysis", arch_design = "//design:sample_seooc_design", - controlmeasures = ["sample_fmea_control_measures.trlc"], - failuremodes = ["sample_fmea_failure_modes.trlc"], + controlmeasures = ["sample_safety_analysis_control_measures.trlc"], + failuremodes = ["sample_safety_analysis_failure_modes.trlc"], root_causes = [":sample_fta"], visibility = ["//visibility:public"], ) diff --git a/bazel/rules/rules_score/examples/seooc/safety_analysis/sample_fmea_control_measures.trlc b/bazel/rules/rules_score/examples/seooc/safety_analysis/sample_safety_analysis_control_measures.trlc similarity index 100% rename from bazel/rules/rules_score/examples/seooc/safety_analysis/sample_fmea_control_measures.trlc rename to bazel/rules/rules_score/examples/seooc/safety_analysis/sample_safety_analysis_control_measures.trlc diff --git a/bazel/rules/rules_score/examples/seooc/safety_analysis/sample_fmea_failure_modes.trlc b/bazel/rules/rules_score/examples/seooc/safety_analysis/sample_safety_analysis_failure_modes.trlc similarity index 100% rename from bazel/rules/rules_score/examples/seooc/safety_analysis/sample_fmea_failure_modes.trlc rename to bazel/rules/rules_score/examples/seooc/safety_analysis/sample_safety_analysis_failure_modes.trlc diff --git a/bazel/rules/rules_score/lobster/config/BUILD b/bazel/rules/rules_score/lobster/config/BUILD index 466b5ef0..51c5f722 100644 --- a/bazel/rules/rules_score/lobster/config/BUILD +++ b/bazel/rules/rules_score/lobster/config/BUILD @@ -12,7 +12,7 @@ # ******************************************************************************* # Lobster-trlc YAML configs and report config templates for S-CORE traceability. -# Used as defaults by rules_score rules (component, dependable_element, fmea, etc.). +# Used as defaults by rules_score rules (component, dependable_element, safety_analysis, etc.). filegroup( name = "component_requirement", diff --git a/bazel/rules/rules_score/private/dependability_analysis.bzl b/bazel/rules/rules_score/private/dependability_analysis.bzl index 2dd5ce9c..2d81a73c 100644 --- a/bazel/rules/rules_score/private/dependability_analysis.bzl +++ b/bazel/rules/rules_score/private/dependability_analysis.bzl @@ -16,7 +16,7 @@ Dependability Analysis build rules for S-CORE projects. A dependability analysis aggregates sub-analysis rules - * **fmea** – ``fmea`` rule targets (failure modes, control + * **safety_analysis** – ``safety_analysis`` rule targets (failure modes, control measures, and optional root cause FTA diagrams). * **security_analysis** – security analysis rule targets (placeholder, optional). @@ -36,7 +36,7 @@ def _collect_analysis_providers(sa, rst_srcs_list, rst_deps_list, rst_aux_list, Updates the provided lists/dicts in-place. Args: - sa: A sub-analysis target (fmea or security). + sa: A sub-analysis target (safety_analysis or security). rst_srcs_list: List of depsets to extend with SphinxSourcesInfo.srcs. rst_deps_list: List of depsets to extend with SphinxSourcesInfo.deps. rst_aux_list: List of depsets to extend with SphinxSourcesInfo.aux_srcs. @@ -81,11 +81,11 @@ def _dependability_analysis_impl(ctx): lobster_files = {} # canonical name → File, merged from all sub-analyses # ------------------------------------------------------------------------- - # Collect from fmea targets + # Collect from safety_analysis targets # ------------------------------------------------------------------------- - fmea_output_files = [] - for sa in ctx.attr.fmea: - fmea_output_files.append(sa[DefaultInfo].files) + safety_analysis_output_files = [] + for sa in ctx.attr.safety_analysis: + safety_analysis_output_files.append(sa[DefaultInfo].files) _collect_analysis_providers(sa, rst_srcs_transitive, rst_deps_transitive, rst_aux_transitive, lobster_files) # ------------------------------------------------------------------------- @@ -173,7 +173,7 @@ def _dependability_analysis_impl(ctx): # ========================================================================= all_output_files = depset( report_files, - transitive = [dfa_rst_files] + fmea_output_files + security_output_files, + transitive = [dfa_rst_files] + safety_analysis_output_files + security_output_files, ) return [ @@ -183,7 +183,7 @@ def _dependability_analysis_impl(ctx): executable = test_executable, ), DependabilityAnalysisInfo( - fmea = depset(transitive = fmea_output_files), + safety_analysis = depset(transitive = safety_analysis_output_files), security_analysis = depset(transitive = security_output_files), dfa = dfa_rst_files, arch_design = arch_design_info, @@ -203,13 +203,13 @@ def _dependability_analysis_impl(ctx): _dependability_analysis_test = rule( implementation = _dependability_analysis_impl, - doc = "Aggregates dependability analysis sub-analyses (fmea, security_analysis) " + + doc = "Aggregates dependability analysis sub-analyses (safety_analysis, security_analysis) " + "and validates the combined traceability chain via lobster-ci-report.", attrs = { - "fmea": attr.label_list( + "safety_analysis": attr.label_list( providers = [AnalysisInfo], mandatory = False, - doc = "fmea rule targets (failure modes + control measures).", + doc = "safety_analysis rule targets (failure modes + control measures).", ), "security_analysis": attr.label_list( providers = [AnalysisInfo], @@ -253,7 +253,7 @@ _dependability_analysis_test = rule( def dependability_analysis( name, - fmea = [], + safety_analysis = [], security_analysis = [], dfa = [], arch_design = None, @@ -270,7 +270,7 @@ def dependability_analysis( Args: name: The name of the dependability analysis target. - fmea: Optional list of ``fmea`` rule target labels. + safety_analysis: Optional list of ``safety_analysis`` rule target labels. security_analysis: Optional list of security analysis rule target labels (placeholder -- not yet implemented). dfa: Optional list of ``.rst``/``.md`` DFA documentation files @@ -287,12 +287,12 @@ def dependability_analysis( dependability_analysis( name = "my_da", - fmea = [":my_fmea"], + safety_analysis = [":my_safety_analysis"], ) """ _dependability_analysis_test( name = name, - fmea = fmea, + safety_analysis = safety_analysis, security_analysis = security_analysis, dfa = dfa, arch_design = arch_design, diff --git a/bazel/rules/rules_score/private/fmea.bzl b/bazel/rules/rules_score/private/safety_analysis.bzl similarity index 87% rename from bazel/rules/rules_score/private/fmea.bzl rename to bazel/rules/rules_score/private/safety_analysis.bzl index 11044f4a..af851849 100644 --- a/bazel/rules/rules_score/private/fmea.bzl +++ b/bazel/rules/rules_score/private/safety_analysis.bzl @@ -12,9 +12,9 @@ # ******************************************************************************* """ -FMEA (Failure Mode and Effects Analysis) build rules for S-CORE projects. +Safety analysis (FMEA – Failure Mode and Effects Analysis) build rules for S-CORE projects. -The rule generates a single, failure-mode-centric ``fmea.rst`` page: an +The rule generates a single, failure-mode-centric ``safety_analysis.rst`` page: an overview summary table followed by one section per failure mode. Each section carries the full failure-mode safety attributes, the fault-tree diagram inline (``.. uml::``), and a "Control Measures" subsection holding only that chain's @@ -28,9 +28,9 @@ Pipeline: metamodel-inlined ``.puml`` (for ``.. uml::``), ``root_causes.lobster`` (``lobster-act-trace``) and ``fta_chains.json`` (the ordered per-failure mode chains). - 2. **Assembly** (``fmea_assembler``) – a single in-process TRLC parse via the + 2. **Assembly** (``safety_analysis_assembler``) – a single in-process TRLC parse via the extended ``TRLCRST`` library renders the overview table and every chain - section into ``fmea.rst``. + section into ``safety_analysis.rst``. 3. **Lobster** (``lobster-trlc``) – FailureMode and ControlMeasure traceability files, unchanged. @@ -63,7 +63,7 @@ def _process_root_causes(ctx): * ``fta_chains.json`` (the ordered per-failure-mode chains). The diagrams are *not* rewritten: each source ``.puml`` is symlinked next to - ``fmea.rst`` so ``.. uml:: `` resolves to the authored diagram. + ``safety_analysis.rst`` so ``.. uml:: `` resolves to the authored diagram. Its ``!include fta_metamodel.puml`` is resolved at render time via the docs toolchain's global PlantUML include path (the metamodel is shipped with the registered ``sphinx_toolchain``), so the metamodel is not staged here. @@ -88,7 +88,7 @@ def _process_root_causes(ctx): ctx.actions.write(chains_json, "[]\n") return [], None, chains_json - # Symlink each authored diagram next to fmea.rst so ``.. uml:: `` + # Symlink each authored diagram next to safety_analysis.rst so ``.. uml:: `` # resolves in the Sphinx tree. diagram_aux_files = [] for src in puml_inputs: @@ -138,19 +138,19 @@ def _lobster_trlc(ctx, trlc_files, config, out_name): # Private Rule Implementation # ============================================================================ -def _fmea_impl(ctx): +def _safety_analysis_impl(ctx): output_files = [] # 0. FTA: extract chains/lobster + stage diagrams (and metamodel) for rendering. diagram_aux_files, root_causes_lobster, chains_json = _process_root_causes(ctx) output_files.extend(diagram_aux_files) - # 1. Assemble fmea.rst from the chains + TRLC records (single in-process parse). - fmea_rst = ctx.actions.declare_file("{}/fmea.rst".format(ctx.label.name)) + # 1. Assemble safety_analysis.rst from the chains + TRLC records (single in-process parse). + safety_analysis_rst = ctx.actions.declare_file("{}/safety_analysis.rst".format(ctx.label.name)) title = ctx.label.name args = ctx.actions.args() - args.add("--output", fmea_rst.path) + args.add("--output", safety_analysis_rst.path) args.add("--template", ctx.file._template.path) args.add("--title", title) args.add("--chains", chains_json.path) @@ -171,12 +171,12 @@ def _fmea_impl(ctx): ctx.files.spec + [chains_json, ctx.file._template] ), - outputs = [fmea_rst], - executable = ctx.executable._fmea_assembler, + outputs = [safety_analysis_rst], + executable = ctx.executable._safety_analysis_assembler, arguments = [args], - progress_message = "Assembling FMEA page for %s" % ctx.label.name, + progress_message = "Assembling safety-analysis page for %s" % ctx.label.name, ) - output_files.append(fmea_rst) + output_files.append(safety_analysis_rst) # 2. lobster-trlc traceability for FailureMode / ControlMeasure records. fm_lobster = _lobster_trlc(ctx, ctx.files.failuremodes, ctx.file._fm_lobster_config, "failuremodes.lobster") @@ -193,8 +193,8 @@ def _fmea_impl(ctx): # The preprocessed .puml diagrams are referenced inline via ``.. uml::`` but # must not be toctree documents, so they travel as aux_srcs (symlinked - # alongside fmea.rst by dependable_element without being indexed). - sphinx_srcs = depset([fmea_rst]) + # alongside safety_analysis.rst by dependable_element without being indexed). + sphinx_srcs = depset([safety_analysis_rst]) return [ DefaultInfo( @@ -215,9 +215,9 @@ def _fmea_impl(ctx): # Rule Definition # ============================================================================ -_fmea = rule( - implementation = _fmea_impl, - doc = "Renders a failure-mode-centric FMEA page (overview table + one chain " + +_safety_analysis = rule( + implementation = _safety_analysis_impl, + doc = "Renders a failure-mode-centric safety-analysis page (overview table + one chain " + "section per failure mode) and lobster traceability files. " + "Build-only rule; traceability testing is owned by dependability_analysis.", attrs = dict( @@ -258,12 +258,12 @@ _fmea = rule( doc = "puml_cli binary used in FTA mode to inline the metamodel and " + "extract root_causes.lobster + fta_chains.json.", ), - "_fmea_assembler": attr.label( - default = Label("//bazel/rules/rules_score:fmea_assembler"), + "_safety_analysis_assembler": attr.label( + default = Label("//bazel/rules/rules_score:safety_analysis_assembler"), executable = True, allow_files = True, cfg = "exec", - doc = "FMEA page assembler (imports the extended TRLCRST library).", + doc = "Safety-analysis page assembler (imports the extended TRLCRST library).", ), "_lobster_trlc": attr.label( default = Label("@lobster//:lobster-trlc"), @@ -283,9 +283,9 @@ _fmea = rule( doc = "lobster-trlc YAML config for ControlMeasure records.", ), "_template": attr.label( - default = Label("//bazel/rules/rules_score:templates/fmea.template.rst"), + default = Label("//bazel/rules/rules_score:templates/safety_analysis.template.rst"), allow_single_file = True, - doc = "RST template for the FMEA page (single ``{body}`` placeholder).", + doc = "RST template for the safety-analysis page (single ``{body}`` placeholder).", ), }, **VERBOSITY_ATTR @@ -296,7 +296,7 @@ _fmea = rule( # Public Macro # ============================================================================ -def fmea( +def safety_analysis( name, spec = None, failuremodes = [], @@ -304,9 +304,9 @@ def fmea( root_causes = [], arch_design = None, **kwargs): - """Define FMEA (Failure Mode and Effects Analysis) following S-CORE process guidelines. + """Define a safety analysis (FMEA – Failure Mode and Effects Analysis) following S-CORE process guidelines. - Generates a single, failure-mode-centric ``fmea.rst`` page: an overview + Generates a single, failure-mode-centric ``safety_analysis.rst`` page: an overview summary table followed by one section per failure mode (failure-mode detail, the fault tree inline, and that chain's control measures). @@ -330,7 +330,7 @@ def fmea( arch_design: Optional ``architectural_design`` target for traceability. **kwargs: Additional arguments (e.g. ``visibility``, ``tags``). """ - _fmea( + _safety_analysis( name = name, spec = spec, failuremodes = failuremodes, diff --git a/bazel/rules/rules_score/providers.bzl b/bazel/rules/rules_score/providers.bzl index 7a612d1b..b06f9a83 100644 --- a/bazel/rules/rules_score/providers.bzl +++ b/bazel/rules/rules_score/providers.bzl @@ -224,11 +224,11 @@ DependabilityAnalysisInfo = provider( doc = """Provider for dependability analysis artifacts. Aggregates sub-analyses: - * **fmea** – fmea rule targets (FM + CM + optional root causes). + * **safety_analysis** – safety_analysis rule targets (FM + CM + optional root causes). * **security_analysis** – security analysis targets (placeholder). """, fields = { - "fmea": "Depset of output files from fmea targets.", + "safety_analysis": "Depset of output files from safety_analysis targets.", "security_analysis": "Depset of output files from security analysis targets.", "dfa": "Depset of DFA documentation files (placeholder).", "arch_design": "ArchitecturalDesignInfo from the linked architectural design (placeholder).", diff --git a/bazel/rules/rules_score/rules_score.bzl b/bazel/rules/rules_score/rules_score.bzl index 9a6cb8e8..85b0ae42 100644 --- a/bazel/rules/rules_score/rules_score.bzl +++ b/bazel/rules/rules_score/rules_score.bzl @@ -53,14 +53,14 @@ load( "//bazel/rules/rules_score/private:filter_execpath.bzl", _filter_execpath = "filter_execpath", ) -load( - "//bazel/rules/rules_score/private:fmea.bzl", - _fmea = "fmea", -) load( "//bazel/rules/rules_score/private:glossary.bzl", _glossary = "glossary", ) +load( + "//bazel/rules/rules_score/private:safety_analysis.bzl", + _safety_analysis = "safety_analysis", +) load( "//bazel/rules/rules_score/private:sphinx_module.bzl", _sphinx_module = "sphinx_module", @@ -82,7 +82,7 @@ dependability_analysis = _dependability_analysis feature_requirements = _feature_requirements glossary = _glossary filter_execpath = _filter_execpath -fmea = _fmea +safety_analysis = _safety_analysis sphinx_module = _sphinx_module unit = _unit unit_design = _unit_design diff --git a/bazel/rules/rules_score/src/fmea_assembler.py b/bazel/rules/rules_score/src/safety_analysis_assembler.py similarity index 98% rename from bazel/rules/rules_score/src/fmea_assembler.py rename to bazel/rules/rules_score/src/safety_analysis_assembler.py index 655b2a58..09e6461b 100644 --- a/bazel/rules/rules_score/src/fmea_assembler.py +++ b/bazel/rules/rules_score/src/safety_analysis_assembler.py @@ -10,7 +10,7 @@ # # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* -"""Assemble a failure-mode-centric ``fmea.rst`` page. +"""Assemble a failure-mode-centric ``safety_analysis.rst`` page. The page is pivoted around the safety chain: an overview summary table followed by one section per failure mode, each containing the failure-mode detail, the @@ -78,7 +78,7 @@ def _indent(text: str, n: int = 3) -> str: def _anchor(fqn: str) -> str: """Sphinx cross-reference label derived from a fully-qualified name.""" - return "fmea-" + re.sub(r"[^0-9a-zA-Z]+", "-", fqn).strip("-").lower() + return "safety-analysis-" + re.sub(r"[^0-9a-zA-Z]+", "-", fqn).strip("-").lower() def _ref(fqn: str, name: str) -> str: @@ -281,7 +281,7 @@ def _build_body(renderer: TRLCRST, chains: list, title: str) -> str: def main() -> None: parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--output", required=True, help="Output fmea.rst path.") + parser.add_argument("--output", required=True, help="Output safety_analysis.rst path.") parser.add_argument("--template", required=True, help="RST template path.") parser.add_argument("--title", required=True, help="Page title.") parser.add_argument( diff --git a/bazel/rules/rules_score/templates/fmea.template.rst b/bazel/rules/rules_score/templates/safety_analysis.template.rst similarity index 100% rename from bazel/rules/rules_score/templates/fmea.template.rst rename to bazel/rules/rules_score/templates/safety_analysis.template.rst diff --git a/bazel/rules/rules_score/test/BUILD b/bazel/rules/rules_score/test/BUILD index 5df54825..ca0401c3 100644 --- a/bazel/rules/rules_score/test/BUILD +++ b/bazel/rules/rules_score/test/BUILD @@ -26,7 +26,7 @@ load( "dependability_analysis", "dependable_element", "feature_requirements", - "fmea", + "safety_analysis", "sphinx_module", "unit", "unit_design", @@ -429,15 +429,15 @@ dependable_element( ) # - Safety Analysis (DFA): wp__sw_component_dfa -# - Safety Analysis (FMEA): wp__sw_component_fmea +# - Safety Analysis (FMEA): wp__sw_component_safety_analysis dependability_analysis( name = "dependability_analysis_target", arch_design = ":arch_design", dfa = ["fixtures/seooc_test/dfa.rst"], - fmea = [":samplelibrary_safety_analysis"], + safety_analysis = [":samplelibrary_safety_analysis"], ) -fmea( +safety_analysis( name = "samplelibrary_safety_analysis", # TODO: add failure modes, control measures, and root causes here # failuremodes = [], @@ -570,8 +570,8 @@ architectural_design( # dependability_analysis_target/samplelibrary_safety_analysis fixture used by # other targets in this file is deliberately empty, so this scenario gets its # own minimal FMEA that traces to "package_pub.PublicInterface". -fmea( - name = "public_api_example_fmea", +safety_analysis( + name = "public_api_example_safety_analysis", arch_design = ":arch_design_public_api_example", failuremodes = ["fixtures/clickable_example/public_api_failure_modes.trlc"], root_causes = ["fixtures/clickable_example/public_api_fta.puml"], @@ -580,7 +580,7 @@ fmea( dependability_analysis( name = "public_api_example_dependability_analysis", arch_design = ":arch_design_public_api_example", - fmea = [":public_api_example_fmea"], + safety_analysis = [":public_api_example_safety_analysis"], ) dependable_element( @@ -746,11 +746,11 @@ architectural_design( ) # public_api items must be referenced by a FailureMode in the SEooC's own -# safety analysis (see :public_api_example_fmea above for the same reasoning) +# safety analysis (see :public_api_example_safety_analysis above for the same reasoning) # - the shared dependability_analysis_target fixture is deliberately empty, so # this scenario gets its own minimal FMEA that traces to "TaskInterface". -fmea( - name = "dynamic_example_fmea", +safety_analysis( + name = "dynamic_example_safety_analysis", arch_design = ":arch_design_dynamic_example", failuremodes = ["fixtures/clickable_example/dynamic_public_api_failure_modes.trlc"], root_causes = ["fixtures/clickable_example/dynamic_public_api_fta.puml"], @@ -759,7 +759,7 @@ fmea( dependability_analysis( name = "dynamic_example_dependability_analysis", arch_design = ":arch_design_dynamic_example", - fmea = [":dynamic_example_fmea"], + safety_analysis = [":dynamic_example_safety_analysis"], ) dependable_element( @@ -1759,10 +1759,10 @@ trlc_requirements_test( ) py_test( - name = "test_fmea_assembler", + name = "test_safety_analysis_assembler", size = "small", - srcs = ["test_fmea_assembler.py"], - deps = ["@score_tooling//bazel/rules/rules_score:fmea_assembler"], + srcs = ["test_safety_analysis_assembler.py"], + deps = ["@score_tooling//bazel/rules/rules_score:safety_analysis_assembler"], ) py_test( @@ -1827,8 +1827,8 @@ test_suite( ":sphinx_module_tests", ":test_aou_forwarding_to_lobster", ":test_bazel_sphinx_needs", - ":test_fmea_assembler", ":test_rst_to_trlc", + ":test_safety_analysis_assembler", ":test_sphinx_html_merge", ":test_sphinx_module_ext", ":test_trlc_rst_image_rendering", diff --git a/bazel/rules/rules_score/test/fixtures/clickable_example/dynamic_public_api_failure_modes.trlc b/bazel/rules/rules_score/test/fixtures/clickable_example/dynamic_public_api_failure_modes.trlc index a2a29a77..d6e0b5fe 100644 --- a/bazel/rules/rules_score/test/fixtures/clickable_example/dynamic_public_api_failure_modes.trlc +++ b/bazel/rules/rules_score/test/fixtures/clickable_example/dynamic_public_api_failure_modes.trlc @@ -10,7 +10,7 @@ * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -package DynamicExampleFmea +package DynamicExampleSafetyAnalysis import ScoreReq diff --git a/bazel/rules/rules_score/test/fixtures/clickable_example/dynamic_public_api_fta.puml b/bazel/rules/rules_score/test/fixtures/clickable_example/dynamic_public_api_fta.puml index 1bce93b9..6e309dfe 100644 --- a/bazel/rules/rules_score/test/fixtures/clickable_example/dynamic_public_api_fta.puml +++ b/bazel/rules/rules_score/test/fixtures/clickable_example/dynamic_public_api_fta.puml @@ -15,6 +15,6 @@ !include fta_metamodel.puml -$TopEvent("TaskInterface stops responding", "DynamicExampleFmea.TaskInterfaceFailure") +$TopEvent("TaskInterface stops responding", "DynamicExampleSafetyAnalysis.TaskInterfaceFailure") @enduml diff --git a/bazel/rules/rules_score/test/fixtures/clickable_example/public_api_failure_modes.trlc b/bazel/rules/rules_score/test/fixtures/clickable_example/public_api_failure_modes.trlc index 85d78325..16197598 100644 --- a/bazel/rules/rules_score/test/fixtures/clickable_example/public_api_failure_modes.trlc +++ b/bazel/rules/rules_score/test/fixtures/clickable_example/public_api_failure_modes.trlc @@ -10,7 +10,7 @@ * * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -package PublicApiExampleFmea +package PublicApiExampleSafetyAnalysis import ScoreReq diff --git a/bazel/rules/rules_score/test/fixtures/clickable_example/public_api_fta.puml b/bazel/rules/rules_score/test/fixtures/clickable_example/public_api_fta.puml index 61dd2b3d..dfd5f3c0 100644 --- a/bazel/rules/rules_score/test/fixtures/clickable_example/public_api_fta.puml +++ b/bazel/rules/rules_score/test/fixtures/clickable_example/public_api_fta.puml @@ -15,6 +15,6 @@ !include fta_metamodel.puml -$TopEvent("PublicInterface stops responding", "PublicApiExampleFmea.PublicInterfaceFailure") +$TopEvent("PublicInterface stops responding", "PublicApiExampleSafetyAnalysis.PublicInterfaceFailure") @enduml diff --git a/bazel/rules/rules_score/test/test_fmea_assembler.py b/bazel/rules/rules_score/test/test_safety_analysis_assembler.py similarity index 90% rename from bazel/rules/rules_score/test/test_fmea_assembler.py rename to bazel/rules/rules_score/test/test_safety_analysis_assembler.py index db98ace4..1a12a4a1 100644 --- a/bazel/rules/rules_score/test/test_fmea_assembler.py +++ b/bazel/rules/rules_score/test/test_safety_analysis_assembler.py @@ -10,7 +10,7 @@ # # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* -"""Unit tests for the FMEA page assembler layout logic.""" +"""Unit tests for the safety-analysis page assembler layout logic.""" import json import os @@ -18,7 +18,7 @@ import tempfile import unittest -import fmea_assembler as fa +import safety_analysis_assembler as fa class _Type: @@ -82,12 +82,12 @@ def _objs(): class AnchorTest(unittest.TestCase): def test_anchor_is_sanitised_lowercase(self): - self.assertEqual(fa._anchor("Lib.FM_A"), "fmea-lib-fm-a") + self.assertEqual(fa._anchor("Lib.FM_A"), "safety-analysis-lib-fm-a") def test_ref_targets_anchor(self): self.assertEqual( fa._ref("Lib.FM_A", "FM_A"), - ":ref:`FM_A `", + ":ref:`FM_A `", ) @@ -112,7 +112,7 @@ def test_overview_and_chain_section_rendered(self): # FM dropdown titled by its full fqn only (no ASIL in the heading). self.assertIn(".. dropdown:: Lib.FM_A\n", body) self.assertNotIn(".. dropdown:: Lib.FM_A :bdg", body) - self.assertIn(":name: fmea-lib-fm-a", body) + self.assertIn(":name: safety-analysis-lib-fm-a", body) # Attributes as a grid of cards; no inner requirement id. self.assertNotIn(".. requirement:definition::", body) self.assertIn(".. grid:: 2", body) @@ -167,7 +167,7 @@ def test_chain_with_unknown_fm_fqn_logs_warning(self): ] import logging as _logging - with self.assertLogs("fmea_assembler", level=_logging.WARNING) as log: + with self.assertLogs("safety_analysis_assembler", level=_logging.WARNING) as log: body = fa._build_body(self.renderer, chains, "Title") self.assertTrue(any("Lib.NoSuchFM" in m for m in log.output)) # The unknown FM is skipped; the known FMs still render. @@ -197,7 +197,7 @@ def test_chain_missing_puml_raises_valueerror(self): # types the assembler keys on, so main() runs a real TRLCRST parse (catching # contract drift the _FakeRenderer cannot). _RSL = """\ -package TestFmea +package TestSafetyAnalysis type FailureMode { guideword optional String @@ -214,7 +214,7 @@ def test_chain_missing_puml_raises_valueerror(self): """ _FM_TRLC = """\ -package TestFmea +package TestSafetyAnalysis FailureMode FmA { guideword = "TooLate" @@ -226,7 +226,7 @@ def test_chain_missing_puml_raises_valueerror(self): """ _CM_TRLC = """\ -package TestFmea +package TestSafetyAnalysis ControlMeasure CmA { safety = "ASIL_D" @@ -236,7 +236,7 @@ def test_chain_missing_puml_raises_valueerror(self): class MainIntegrationTest(unittest.TestCase): - """End-to-end main(): real TRLCRST parse + chains JSON -> fmea.rst.""" + """End-to-end main(): real TRLCRST parse + chains JSON -> safety_analysis.rst.""" def _write(self, directory, name, content): path = os.path.join(directory, name) @@ -264,19 +264,19 @@ def test_full_page_assembled_from_real_trlc(self): json.dumps( [ { - "fm_fqn": "TestFmea.FmA", + "fm_fqn": "TestSafetyAnalysis.FmA", "fm_name": "Fm A", "puml": "a.puml", - "control_measures": ["TestFmea.CmA"], + "control_measures": ["TestSafetyAnalysis.CmA"], } ] ), ) - out = os.path.join(tmp, "fmea.rst") + out = os.path.join(tmp, "safety_analysis.rst") self._run_main( [ - "fmea_assembler", + "safety_analysis_assembler", "--output", out, "--template", @@ -301,8 +301,8 @@ def test_full_page_assembled_from_real_trlc(self): self.assertIn("Test FMEA", rst) self.assertIn("Overview", rst) self.assertIn(".. list-table::", rst) - self.assertIn(".. dropdown:: TestFmea.FmA\n", rst) - self.assertIn(":name: fmea-testfmea-fma", rst) + self.assertIn(".. dropdown:: TestSafetyAnalysis.FmA\n", rst) + self.assertIn(":name: safety-analysis-testsafetyanalysis-fma", rst) self.assertIn(".. grid-item-card:: Description", rst) self.assertIn(".. rubric:: Root Cause Analysis", rst) self.assertIn(".. uml:: a.puml", rst) @@ -315,11 +315,11 @@ def test_malformed_chains_json_exits_nonzero(self): with tempfile.TemporaryDirectory() as tmp: template = self._write(tmp, "tmpl.rst", "{body}\n") bad = self._write(tmp, "chains.json", "{ this is not json") - out = os.path.join(tmp, "fmea.rst") + out = os.path.join(tmp, "safety_analysis.rst") with self.assertRaises(SystemExit) as ctx: self._run_main( [ - "fmea_assembler", + "safety_analysis_assembler", "--output", out, "--template", @@ -337,11 +337,11 @@ def test_missing_body_placeholder_exits_nonzero(self): # Template without the required {body} placeholder. template = self._write(tmp, "tmpl.rst", "no placeholder here\n") chains = self._write(tmp, "chains.json", "[]") - out = os.path.join(tmp, "fmea.rst") + out = os.path.join(tmp, "safety_analysis.rst") with self.assertRaises(SystemExit) as ctx: self._run_main( [ - "fmea_assembler", + "safety_analysis_assembler", "--output", out, "--template", diff --git a/plantuml/parser/puml_fta/src/lib.rs b/plantuml/parser/puml_fta/src/lib.rs index b4a3ef5e..d79f3805 100644 --- a/plantuml/parser/puml_fta/src/lib.rs +++ b/plantuml/parser/puml_fta/src/lib.rs @@ -22,7 +22,7 @@ //! `dependability_analysis` traceability test is unaffected, and //! * an ordered list of *chains* (`fta_chains.json`) describing, per failure //! mode, the inline diagram and the control measures (basic events) that -//! trace up to it — consumed by the FMEA page assembler. +//! trace up to it — consumed by the safety-analysis page assembler. //! //! [`lobster-act-trace`]: https://github.com/bmw-software-engineering/lobster