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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions bazel/rules/rules_score/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,25 @@ architectural_design(
Diagrams in `public_api` are classified separately so their lobster items flow
through `public_api_lobster_files` for failure-mode traceability.

`static_view` is an optional additional section for component diagrams that
present a partial view of the static architecture (e.g. a diagram scoped to a
subsystem). Diagrams passed to `static_view` are parsed like `static`, but are
never used to define the units/components validated against the Bazel
component graph. Instead, every component/unit defined in a `static_view`
diagram must also be defined, under the same parent, in `static`: it may only
contain a subset of the units/components of the matching `static` diagram.
**`bazel build`** fails if a `static_view` diagram introduces a
component/unit that is not present in `static`.

The `static_view` section can be used for creating additional diagrams that
provide a view onto the architecture which make the design easier to view / understand.
E.g. you can create a diagram which shows a subset of components as showing all
components in one view may be too "busy". It can also be useful when showing the
interfaces between components. Adding all the interfaces in the diagrams in the
`static` view may result in too many interface lines which is not readable. Instead,
a view can be created with a subset of components and only the interfaces between these
chosen components can be shown.

---

## `unit`
Expand Down
11 changes: 8 additions & 3 deletions bazel/rules/rules_score/docs/rule_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -390,15 +390,16 @@ Example glossary source (``.rst``):
architectural_design
~~~~~~~~~~~~~~~~~~~~

Bundles static, dynamic, public-API, and internal-API architecture views into a
single target. Provides ``ArchitecturalDesignInfo`` consumed by ``dependable_element``
and ``fmea``.
Bundles static, dynamic, static-view, public-API, and internal-API architecture
views into a single target. Provides ``ArchitecturalDesignInfo`` consumed by
``dependable_element`` and ``fmea``.

.. code-block:: python

architectural_design(
name = "arch",
static = ["docs/static_design.puml"],
static_view = ["docs/subsystem_view.puml"],
dynamic = ["docs/sequence.puml"],
public_api = ["docs/public_api.puml"],
internal_api = ["docs/internal_api.puml"],
Expand Down Expand Up @@ -432,6 +433,10 @@ and ``fmea``.
- label list
- no
- Internal-API diagram files (``.puml``) describing interfaces exposed between components inside the SEooC; their FlatBuffers output is exposed via ``ArchitecturalDesignInfo.internal_api`` for downstream validation (default ``[]``)
* - ``static_view``
- label list
- no
- Component diagrams (``.puml``, ``.plantuml``) that present a partial view of the static architecture. These can be used to create smaller diagrams which highlight a subset of all components / units to improve readability / understandability. Components and units defined in a static view must also be defined under the same parent in ``static`` (default ``[]``)
* - ``maturity``
- string
- no
Expand Down
38 changes: 32 additions & 6 deletions bazel/rules/rules_score/private/architectural_design.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def _colocate_view_files(ctx, staged_files, view_output_dir):
colocated[relative_path] = copy
return colocated

def _run_validation(ctx, component_fbs_files, sequence_fbs_files, public_api_fbs_files, internal_api_fbs_files):
def _run_validation(ctx, component_fbs_files, sequence_fbs_files, public_api_fbs_files, internal_api_fbs_files, static_view_fbs_files):
"""Run the architectural-design validation profile.

Args:
Expand All @@ -207,6 +207,7 @@ def _run_validation(ctx, component_fbs_files, sequence_fbs_files, public_api_fbs
sequence_fbs_files: Sequence-diagram FlatBuffer files generated from this target's dynamic inputs.
public_api_fbs_files: List of public-API FlatBuffer files generated from this target's public_api inputs.
internal_api_fbs_files: List of internal-API FlatBuffer files generated from this target's internal_api inputs.
static_view_fbs_files: Component-diagram FlatBuffer files generated from this target's static_view inputs.
Returns:
Struct with file and name fields describing the validation log entry.
"""
Expand All @@ -220,8 +221,9 @@ def _run_validation(ctx, component_fbs_files, sequence_fbs_files, public_api_fbs
"sequence_diagrams": [f.path for f in sequence_fbs_files],
"public_api_diagrams": [f.path for f in public_api_fbs_files],
"internal_api_diagrams": [f.path for f in internal_api_fbs_files],
"static_view": [f.path for f in static_view_fbs_files],
},
inputs = component_fbs_files + sequence_fbs_files + public_api_fbs_files + internal_api_fbs_files,
inputs = component_fbs_files + sequence_fbs_files + public_api_fbs_files + internal_api_fbs_files + static_view_fbs_files,
mnemonic = "ArchitecturalDesignValidate",
maturity = ctx.attr.maturity,
log_level = get_log_level(ctx),
Expand All @@ -247,10 +249,10 @@ def _architectural_design_impl(ctx):

# All diagrams of this target share one flat fbs/lobster/idmap namespace
# (keyed by ctx.label.name), so stems must be disambiguated across all
# four views together, not per-view.
# views together, not per-view.
stems = _disambiguated_stems(
ctx,
ctx.files.static + ctx.files.dynamic + ctx.files.public_api + ctx.files.internal_api,
ctx.files.static + ctx.files.dynamic + ctx.files.public_api + ctx.files.internal_api + ctx.files.static_view,
)

view_fbs = {}
Expand Down Expand Up @@ -319,16 +321,17 @@ def _architectural_design_impl(ctx):
public_api_fbs = depset(view_fbs["public_api"])
internal_api_fbs = depset(view_fbs["internal_api"])
public_api_lobster = depset(view_lobster["public_api"])
static_view_fbs = depset(view_fbs["static_view"])

all_source_files = depset(transitive = view_source_files)

# All idmap sidecars (across static/dynamic/public_api/internal_api) are
# All idmap sidecars (across static/dynamic/public_api/internal_api/static_view) are
# staged into the sphinx sources so the `clickable_plantuml` extension can
# discover them (it scans `srcdir` recursively for `*.idmap.json`) and
# resolve cross-diagram links — including component diagrams linking to
# the class diagrams that elaborate their public/internal API interfaces.
all_idmap_files = depset(
view_idmap["static"] + view_idmap["dynamic"] + view_idmap["public_api"] + view_idmap["internal_api"],
view_idmap["static"] + view_idmap["dynamic"] + view_idmap["public_api"] + view_idmap["internal_api"] + view_idmap["static_view"],
)

sphinx_files = depset(
Expand All @@ -341,6 +344,7 @@ def _architectural_design_impl(ctx):
view_fbs["dynamic"],
view_fbs["public_api"],
view_fbs["internal_api"],
view_fbs["static_view"],
)

# `deps` carries everything needed in the Sphinx tree for this rule
Expand All @@ -360,6 +364,7 @@ def _architectural_design_impl(ctx):
dynamic = dynamic_fbs,
public_api = public_api_fbs,
internal_api = internal_api_fbs,
static_view = static_view_fbs,
view_root_indexes = view_root_indexes,
name = ctx.label.name,
public_api_lobster_files = public_api_lobster,
Expand Down Expand Up @@ -406,6 +411,16 @@ def _architectural_design_attrs():
"Classified separately so their FlatBuffers outputs are exposed via " +
"ArchitecturalDesignInfo.internal_api for downstream validation.",
),
"static_view": attr.label_list(
allow_files = [".puml", ".plantuml"],
mandatory = False,
doc = "Component diagrams that present a partial view of the static architecture. " +
"Parsed identically to `static`, but never used to define the units/components " +
"validated against the Bazel component graph. Instead, every component/unit " +
"defined here must also be defined, under the same parent, in `static`; " +
"the build fails if a `static_view` diagram introduces a component/unit that is " +
"not present in the `static` diagrams.",
),
"maturity": attr.string(
default = "release",
values = ["release", "development"],
Expand Down Expand Up @@ -444,6 +459,7 @@ def architectural_design(
dynamic = [],
public_api = [],
internal_api = [],
static_view = [],
maturity = "release",
**kwargs):
"""Define architectural design following S-CORE process guidelines.
Expand Down Expand Up @@ -478,6 +494,15 @@ def architectural_design(
static/dynamic diagrams but classified separately so their
FlatBuffers outputs are exposed via ArchitecturalDesignInfo.
internal_api for downstream validation.
static_view: Optional list of .puml component diagrams that present a
partial view of the static architecture. These are parsed
identically to `static`, but are not used to define the
units/components validated against the Bazel component graph.
Instead, every component/unit defined in a `static_view` diagram
must also be defined, under the same parent, in `static`: it may
only contain a subset of the units/components of the matching
`static` diagram. The build fails if a `static_view` diagram
introduces a component/unit that is not present in `static`.
maturity: Maturity level of the architectural design. Use
"development" to write validation findings without failing the
Bazel action.
Expand Down Expand Up @@ -510,6 +535,7 @@ def architectural_design(
dynamic = dynamic,
public_api = public_api,
internal_api = internal_api,
static_view = static_view,
maturity = maturity,
**kwargs
)
1 change: 1 addition & 0 deletions bazel/rules/rules_score/private/views.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ ARCH_VIEWS = [
("dynamic", "Dynamic Design"),
("public_api", "Public API"),
("internal_api", "Internal API"),
("static_view", "Static View"),
]
3 changes: 2 additions & 1 deletion bazel/rules/rules_score/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ ArchitecturalDesignInfo = provider(
"dynamic": "Depset of FlatBuffers binaries for dynamic architecture diagrams (sequence diagrams, activity diagrams, etc.)",
"public_api": "Depset of FlatBuffers binaries for public API diagrams (class diagrams, etc.)",
"internal_api": "Depset of FlatBuffers binaries for internal API diagrams (class diagrams, etc.)",
"view_root_indexes": "Dict mapping view name ('static', 'dynamic', 'public_api', 'internal_api') to that view's single top-level toctree-entry File (see emit_view_navigation's root_index), or None for views with no navigable files.",
"static_view": "Depset of FlatBuffers binaries for static_view component diagrams (partial views of the static architecture, validated for consistency against static).",
"view_root_indexes": "Dict mapping view name ('static', 'dynamic', 'public_api', 'internal_api', 'static_view') to that view's single top-level toctree-entry File (see emit_view_navigation's root_index), or None for views with no navigable files.",
"name": "Name of the architectural design target",
"public_api_lobster_files": "Depset of .lobster traceability files generated from public_api diagrams.",
"validation_logs": "List of validation log entries produced by this architectural design target. Each entry has file and name fields.",
Expand Down
61 changes: 61 additions & 0 deletions bazel/rules/rules_score/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,67 @@ dependable_element(
deps = [],
)

# Demonstrates architectural_design's `static_view` attribute: `static_view`
# diagrams are parsed like `static`, but never define the units/components
# validated against the Bazel component graph. Instead, every component/unit
# defined in a `static_view` diagram must also be defined, under the same
# parent, in `static` -- here, static_view_overview.puml (component_sv with a
# single child unit_sv) is a consistent subset of static_view_static.puml
# (component_sv with unit_sv AND unit_sv_extra), so `bazel build` succeeds.
# The static-vs-static_view consistency check itself (including the
# build-failure case when a static_view diagram introduces an entity absent
# from static) is covered by validate_static_view_consistency's Rust unit
# tests in validation/core/src/validators/test/static_view_consistency_validator_test.rs.
#
# public_api is also wired in (static_view_detail.puml, defining
# `package_sv.SvInterface`) so this example also exercises the general
# "every public API interface item must be referenced by a FailureMode"
# traceability requirement (see fmea/dependability_analysis below) for a
# target that also uses `static_view` -- mirroring the fmea/dependability_
# analysis wiring from the original static_view example fixture.
architectural_design(
name = "arch_design_static_view_example",
public_api = ["fixtures/clickable_example/static_view_detail.puml"],
static = ["fixtures/clickable_example/static_view_static.puml"],
static_view = ["fixtures/clickable_example/static_view_overview.puml"],
)

# public_api items must be referenced by a FailureMode in the SEooC's own
# safety analysis - same requirement as public_api_example_fmea above.
fmea(
name = "static_view_example_fmea",
arch_design = ":arch_design_static_view_example",
failuremodes = ["fixtures/clickable_example/static_view_failure_modes.trlc"],
root_causes = ["fixtures/clickable_example/static_view_fta.puml"],
)

dependability_analysis(
name = "static_view_example_dependability_analysis",
arch_design = ":arch_design_static_view_example",
fmea = [":static_view_example_fmea"],
)

dependable_element(
name = "static_view_example_lib",
architectural_design = [":arch_design_static_view_example"],
assumptions_of_use = [":aous"],
components = [],
dependability_analysis = [":static_view_example_dependability_analysis"],
integrity_level = "B",
# Downgraded to warnings for two reasons: (1) this fixture's `static`
# diagram declares package_sv/component_sv/unit_sv purely to demonstrate
# the static_view attribute and its consistency check, with no matching
# Bazel component/unit targets (same reasoning as unit_example_lib
# above); (2) it intentionally reuses "SvInterface" as both a reference
# and a definition, which the dependable-element validator can't
# distinguish from an accidental duplicate id (same reasoning as
# clickable_example_lib above).
maturity = "development",
requirements = [":feat_req"],
tests = [],
deps = [],
)

# Live example of clickable_plantuml's "unit to class diagram" linking chain:
# the *static* architecture (unit_overview.puml, a component diagram) shows
# `unit_one` as a leaf unit (no children) - a reference - and
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
' *******************************************************************************
' Copyright (c) 2026 Contributors to the Eclipse Foundation
'
' See the NOTICE file(s) distributed with this work for additional
' information regarding copyright ownership.
'
' This program and the accompanying materials are made available under the
' terms of the Apache License Version 2.0 which is available at
' https://www.apache.org/licenses/LICENSE-2.0
'
' SPDX-License-Identifier: Apache-2.0
' *******************************************************************************

@startuml SvInterface

package package_sv {
interface "SvInterface" as SvInterface
}

@enduml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/********************************************************************************
* Copyright (c) 2026 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
package StaticViewExampleFmea

import ScoreReq

ScoreReq.FailureMode SvInterfaceFailure {
guidewords = [ScoreReq.Guideword.LossOfFunction]
description = "SvInterface stops responding"
failureeffect = "Callers never receive a response"
version = 1
safety = ScoreReq.Asil.B
interface = "package_sv.SvInterface"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
' *******************************************************************************
' Copyright (c) 2026 Contributors to the Eclipse Foundation
'
' See the NOTICE file(s) distributed with this work for additional
' information regarding copyright ownership.
'
' This program and the accompanying materials are made available under the
' terms of the Apache License Version 2.0 which is available at
' https://www.apache.org/licenses/LICENSE-2.0
'
' SPDX-License-Identifier: Apache-2.0
' *******************************************************************************

@startuml

!include fta_metamodel.puml

$TopEvent("SvInterface stops responding", "StaticViewExampleFmea.SvInterfaceFailure")

@enduml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
' *******************************************************************************
' Copyright (c) 2026 Contributors to the Eclipse Foundation
'
' See the NOTICE file(s) distributed with this work for additional
' information regarding copyright ownership.
'
' This program and the accompanying materials are made available under the
' terms of the Apache License Version 2.0 which is available at
' https://www.apache.org/licenses/LICENSE-2.0
'
' SPDX-License-Identifier: Apache-2.0
' *******************************************************************************

@startuml static_view_overview

package "Package Sv" as package_sv {
component "Component Sv" as component_sv <<component>> {
component "Unit Sv" as unit_sv <<unit>>
}

interface "SvInterface" as SvInterface
unit_sv -( SvInterface
}

@enduml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
' *******************************************************************************
' Copyright (c) 2026 Contributors to the Eclipse Foundation
'
' See the NOTICE file(s) distributed with this work for additional
' information regarding copyright ownership.
'
' This program and the accompanying materials are made available under the
' terms of the Apache License Version 2.0 which is available at
' https://www.apache.org/licenses/LICENSE-2.0
'
' SPDX-License-Identifier: Apache-2.0
' *******************************************************************************

@startuml static_view_static

package "Package Sv" as package_sv {
component "Component Sv" as component_sv <<component>> {
component "Unit Sv" as unit_sv <<unit>>
component "Unit Sv Extra" as unit_sv_extra <<unit>>
}
}

@enduml
2 changes: 2 additions & 0 deletions validation/core/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,14 @@ rust_library(
"src/validators/shared/diagram_analysis.rs",
"src/validators/shared/helpers.rs",
"src/validators/shared/mod.rs",
"src/validators/static_view_consistency_validator.rs",
"src/validators/test/class_design_sequence_validator_test.rs",
"src/validators/test/component_internal_api_validator_test.rs",
"src/validators/test/component_public_api_validator_test.rs",
"src/validators/test/component_sequence_validator_test.rs",
"src/validators/test/fixtures.rs",
"src/validators/test/sequence_internal_api_validator_test.rs",
"src/validators/test/static_view_consistency_validator_test.rs",
],
crate_root = "src/lib.rs",
visibility = ["//visibility:public"],
Expand Down
Loading
Loading