STIG Help

How diagram cells are counted

When you run stigGenerateHtml, stig produces a fixed-shape grid of diagrams per activity. The grid is the cross-product of 5 axes. This page documents what each axis means, how many values it can take, and how the per-activity cell count is derived — so you can read the lifecycle log and reason about what's enabled vs. what's generated.

The 5 axes

#

Axis

Values

Count

Where it's decided

1

analysis_type

data_and_control_flow_analysis, cascading_failure_analysis, control_flow_analysis

3

Which sourceCodeAnalysis { … } block the user enabled

2

depth

per_group, per_leaf

2

How fine the cfg slicing is — one cfg per group, or one per leaf

3

merge_mode

all_sinks, one_sink

2

One cfg combines all sinks, or one cfg per individual sink

4

diagram_type

data_flow_diagram, control_flow_diagram, combined_data_and_control_flow_diagram, plus diagnostic enum values icfg_diagram and data_restricted_control_flow_diagram

5 max

Rendering only — derived from a single analysis.json; DSL toggles currently expose the first three

5

summary_type

detailed_per_ir_instruction, detailed_per_segment, summarized

3 max

Rendering only — same analysis.json, multiple views

Axes 1–3 are input axes — each combination drives one cfg.json (input to the analyzer) and one analysis.json (output from the analyzer). Axes 4–5 are output axes — each analysis.json is rendered into multiple cells from the same data.

Theoretical total

3 (analysis_type) × 2 (depth) × (1 + N) (slugs) × enabled diagram/summary cells

where N is the number of configured one_sink slugs in the activity (+1 covers the literal all_sinks slug). The merge_mode axis is absorbed into (1 + N) — all_sinks is one slug, one_sink is N slugs.

The runtime log first prints the full enum cross-product as analyses × diagramTypes × summaryTypes. It then subtracts diagram types disabled by DSL and invalid axis pairs. Today detailed_per_segment is valid only with data_flow_diagram, and detailed_per_ir_instruction is valid only with control_flow_diagram. Data-flow diagrams render summarized and detailed_per_segment; control-flow diagrams render summarized and detailed_per_ir_instruction.

Worked example — example_activity

Configured sinks: 9 cascading sinks in cascadingFailuresAnalysis, 14 data-flow sinks in dataAndControlFlowAnalysis.

Today the activity only uses per_leaf (no per_group) and only two of the three analysis kinds:

analysis_type

depth

merge_mode

slugs

analysis.json count

data_and_control_flow_analysis

per_leaf

one_sink

14 sinks

14

data_and_control_flow_analysis

per_leaf

all_sinks

1 (all_sinks)

1

cascading_failure_analysis

per_leaf

one_sink

9 sinks

9

cascading_failure_analysis

per_leaf

all_sinks

1 (all_sinks)

1

With the default DCF/CAS diagram toggles (data_flow_diagram and control_flow_diagram enabled, combined disabled), each analysis renders four valid interactive cells:

  • data_flow_diagram: summarized, detailed_per_segment

  • control_flow_diagram: summarized, detailed_per_ir_instruction

Plugging into the formula per (analysis_type, depth):

DCF, per_leaf : 4 × (1 + 14) = 60 cells CAS, per_leaf : 4 × (1 + 9) = 40 cells ───────────────────────────────────── Total 100 enabled valid cells

Equivalently in axis-product form (which is how the runtime log phrases it):

analyses (25) × enabled valid diagram/summary cells (4) = 100

If you set showCombinedDataAndControlFlowDiagrams = false in the DSL (turning off diagram_type = combined_data_and_control_flow_diagram for both DCF and CAS), the combined cells stay disabled. The combined diagram type currently has only the summarized summary type in the matrix:

25 × 5 = 125 enabled valid cells

What each summary_type shows

The same analysis.json data, rendered at multiple granularities:

  • detailed_per_ir_instruction — every LLVM instruction in the selected rendered control-flow view is one node. Edges come from the analyzer ICFG. This summary type is not generated for data-flow diagrams unless a future analyzer schema emits exact IR-to-IR data-flow edges. For a non-trivial leaf this can be 100+ nodes.

  • detailed_per_segment — data-flow only. Each analyzer sinks[].dataFlowDAG.segments[] entry is one node; its tooltip lists the ordered IR instructions belonging to that segment. One IR can appear in multiple segment tooltips because segments are DAG metadata, not strict parents.

  • summarized — instructions are folded into their enclosing function. For data flow, source-to-sink relations are contracted over the analyzer segment DAG. For control flow, relations are contracted over ICFG paths. This is the high-level "which functions are on the path" view.

Both come from the same analyzer run; the fan-out is pure rendering — no extra analyzer cost.

Reading the lifecycle log

At the end of stigAnalysisP7GenerateDiagrams you'll see a summary line like:

stigGenerateDiagrams summary: rendered 100 cells / analyses: 25 with content, 0 empty / skipped cells: 50 disabled by DSL, 0 empty after transform / source files: 25

What each number means:

  • source files: 25 — number of analysis.json files the task found under stigAnalysisP6RunAnalyzer/analyzer/….

  • analyses: X with content, Y empty — of those, how many produced at least one rendered Vista node from controlFlowGraph or per-sink dataFlowDAG content. The "empty" ones get surfaced separately in the ## Empty analyses section of diagrams.md (see .no-data.txt markers).

  • rendered N cells — successful renders of (analysis × diagram_type × summary_type).

  • skipped cells: M disabled by DSL — cells that were never attempted because the user's DSL turned off the diagram_type for the analysis kind.

  • invalid axis combinations: M diagrams — enum combinations that are intentionally not rendered, currently detailed_per_segment with any non-data-flow diagram type and detailed_per_ir_instruction with any non-control-flow diagram type.

  • K empty after transform — cells where the analysis had data but Transform.transform(diagramType, summaryType) pruned it to zero nodes. This is the case the diagram-completeness validator fails on (severity gated by failAt), because the input had data but the renderer produced nothing — a real loss of signal.

rendered + disabled-by-DSL + empty-after-transform + (cells from empty analyses) should equal the theoretical total for the cfg inventory shown above.

23 October 2026