# How the Seven Semantic Patterns Route to Specific Visual Types

> Discover how the seven semantic patterns route to specific visual types using a lookup table with conditional fallbacks for specialized diagramming needs. Learn more today.

- Repository: [Cathryn Lavery/diagram-design](https://github.com/cathrynlavery/diagram-design)
- Tags: deep-dive
- Published: 2026-08-14

---

**The seven semantic patterns route to visual types via a lookup table defined in [`references/semantic-patterns.md`](https://github.com/cathrynlavery/diagram-design/blob/main/references/semantic-patterns.md), where each pattern maps to its nearest visual type with conditional fallbacks for specialized cases.**

This routing system is the core decision engine of the **diagram-design** skill. It separates *what* a diagram communicates (behaviour) from *how* it is laid out (visual grammar). When you trigger a diagram generation, the skill evaluates your behavioural context against seven defined patterns, then selects the optimal visual type to render that meaning.

## The Semantic-to-Visual Routing Table

The mappings live in [`references/semantic-patterns.md`](https://github.com/cathrynlavery/diagram-design/blob/main/references/semantic-patterns.md) and are enforced by [`scripts/verify-semantic-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/verify-semantic-motion.py). Each pattern routes to a primary visual type, with alternatives triggered by specific structural conditions.

| Pattern | Nearest Visual Type | Fallback Condition |
|---------|---------------------|------------------|
| **Fan-in queue / bottleneck** | Data flow | Process — when service stages dominate over queue flow |
| **Stage framework with semantic slots** | Process | Swimlane — when rows represent owners rather than slots |
| **Unstructured input → structured artifact** | Data flow | Process — when elicitation has several ordered gates |
| **Paired policy-evaluation traces** | Flowchart | Sequence — when time-ordered messages are load-bearing |
| **Secure paved road** | Architecture | *(none)* |
| **Governance / control catalog** | Layer stack | DP security matrix — when role-based permissions dominate |
| **Compensating security layers** | Layer stack | Nested — when containment boundaries, not ordered compensation, carry meaning |

## Pattern-by-Pattern Routing Logic

### Fan-In Queue / Bottleneck → Data Flow (or Process)

A queue-oriented story—multiple sources feeding a single constrained service—maps naturally to **data flow** diagrams. The visual emphasizes movement from sources to the bottleneck.

When the diagram focuses on the service stages themselves rather than the queue dynamic, the router falls back to **Process**. This switch is governed by which element carries the primary semantic weight: flow versus stage structure.

### Stage Framework with Semantic Slots → Process (or Swimlane)

Repeated structures like "Question → Input → Governance → Output" across stages create a tabular matrix. The **Process** type renders this through ordered rows and columns.

Switch to **Swimlane** only when rows represent *owners* (teams, roles, systems) rather than semantic slots. This distinction is captured in the pattern's routing flags.

### Unstructured Input → Structured Artifact → Data Flow (or Process)

Free-form input transforming into a durable artifact follows a classic data-flow story: inputs converge, undergo transformation, and yield the structured result.

The **Process** fallback activates when the input elicitation involves several ordered gates—sequential checkpoints that create a stage-like structure.

### Paired Policy-Evaluation Traces → Flowchart (or Sequence)

Comparing two rule traces (PASS / FAIL / SKIPPED states) is fundamentally a decision-logic problem. **Flowchart** provides the branching node vocabulary this semantics requires.

The **Sequence** alternative applies only when time-ordered messages between components are themselves load-bearing information—not merely implementation detail.

### Secure Paved Road → Architecture

Trust boundaries, permitted/forbidden ingress paths, and deployment routing are architectural concerns. The **Architecture** type's zones and boundary conventions make these security semantics explicit. No fallback is needed; this mapping is unconditional.

### Governance / Control Catalog → Layer Stack (or DP Security Matrix)

Grouping controls by enforcement surface produces a stacked view of layers. The **Layer stack** visual type renders this stratification.

When the dominant comparison shifts from *enforcement surface* to *role-based permissions*, the router selects the **DP security matrix** variant instead.

### Compensating Security Layers → Layer Stack (or Nested)

A sequence of defensive layers reducing risk is the canonical **Layer stack** story—ordered compensation where sequence matters.

Switch to **Nested** when the meaning derives from *containment boundaries* rather than *ordered compensation*. The router detects this via the presence of hierarchy markers versus sequence markers in the semantic model.

## How the Router Executes

The workflow follows this sequence, as documented in [`SKILL.md`](https://github.com/cathrynlavery/diagram-design/blob/main/SKILL.md) (see "Selection: semantic pattern, then visual type"):

```python

# 1. Load the semantic-patterns reference

patterns = load_md('references/semantic-patterns.md')

# 2. Choose pattern matching the behavioural trigger

chosen_pattern = select_pattern(behavior_trigger)

# 3. Look up nearest visual type from routing table

visual_type = patterns.routing_table[chosen_pattern]

# 4. Load visual-type reference before drawing

type_md = load_md(f'references/type-{visual_type.lower().replace(" ", "-")}.md')

# 5. Render using the layout grammar of type_md

render_diagram(semantic_model, type_md)

```

The `select_pattern()` function evaluates trigger conditions against pattern definitions. The `routing_table` dictionary returns the primary visual type, with conditional logic applying fallbacks based on model properties.

## Code Examples: Routing in Practice

### Fan-In Queue → Data Flow

```python
from diagram_design import Diagram, load_pattern, load_type

model = Diagram()
model.add_queue(
    name='Review Queue',
    sources=['PR-1', 'PR-2', 'PR-3'],
    bottleneck='Gatekeeper',
    outcomes=['Approved', 'Rejected']
)

pattern = load_pattern('Fan-in queue / bottleneck')
vtype = pattern.nearest_visual_type   # => 'Data flow'

type_ref = load_type(vtype)           # loads type-data-flow.md

svg = model.render(type_ref)

print(svg)

```

### Secure Paved Road → Architecture

```python
from diagram_design import Diagram, load_pattern, load_type

model = Diagram()
model.add_trust_boundary(
    name='Production',
    permitted=['Deploy-svc', 'Config-svc'],
    forbidden=['Debug-svc'],
    privileged='Ops-gate'
)

pattern = load_pattern('Secure paved road')
vtype = pattern.nearest_visual_type   # => 'Architecture'

type_ref = load_type(vtype)           # loads type-architecture.md

svg = model.render(type_ref)

print(svg)

```

Both examples use `load_pattern()` and `load_type()`, which parse the markdown references in [`references/semantic-patterns.md`](https://github.com/cathrynlavery/diagram-design/blob/main/references/semantic-patterns.md) and `references/type-*.md` respectively. The rendering engine consumes the layout grammar defined in those type-specific files.

## Key Files in the Routing System

| File | Purpose |
|------|---------|
| [`references/semantic-patterns.md`](https://github.com/cathrynlavery/diagram-design/blob/main/references/semantic-patterns.md) | Source of truth for pattern → visual-type mappings |
| [`SKILL.md`](https://github.com/cathrynlavery/diagram-design/blob/main/SKILL.md) | User-facing documentation of the selection flow |
| [`scripts/verify-semantic-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/verify-semantic-motion.py) | Validates that [`SKILL.md`](https://github.com/cathrynlavery/diagram-design/blob/main/SKILL.md) links match routing table |
| `references/type-*.md` | Layout grammar for each visual type (e.g., [`type-data-flow.md`](https://github.com/cathrynlavery/diagram-design/blob/main/type-data-flow.md), [`type-architecture.md`](https://github.com/cathrynlavery/diagram-design/blob/main/type-architecture.md)) |
| `assets/template-*.html` | Final HTML output templates embedding rendered SVG |

## Summary

- **Seven semantic patterns** capture behavioural intent, separate from visual layout concerns.
- **Routing table in [`semantic-patterns.md`](https://github.com/cathrynlavery/diagram-design/blob/main/semantic-patterns.md)** maps each pattern to its nearest visual type.
- **Conditional fallbacks** activate based on structural properties: owner lanes trigger Swimlane, ordered gates trigger Process, role permissions trigger DP security matrix, containment triggers Nested.
- **Verification script [`verify-semantic-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/verify-semantic-motion.py)** ensures documentation and code stay synchronized.
- **Runtime workflow** loads pattern → resolves type → loads type grammar → renders diagram.

## Frequently Asked Questions

### How does the router choose between a primary visual type and its fallback?

The router inspects properties of the semantic model. For "Stage framework with semantic slots", it checks whether rows represent *owners* (triggers Swimlane) or *slots* (uses Process). These conditions are encoded in the pattern definitions within [`references/semantic-patterns.md`](https://github.com/cathrynlavery/diagram-design/blob/main/references/semantic-patterns.md).

### Can I override the automatic routing to force a specific visual type?

The current implementation routes through `pattern.nearest_visual_type`. Direct override would require bypassing `load_pattern()` and manually specifying a type to `load_type()`. The design prioritizes semantic fidelity over manual control—incorrect type choices risk misrepresenting the behaviour being modeled.

### What happens if my diagram matches multiple semantic patterns?

The `select_pattern()` function uses trigger priority: more specific patterns win over general ones. "Secure paved road" (specific trust boundary semantics) outranks generic "Governance / control catalog" when both conditions are present. Ties are resolved by declaration order in [`semantic-patterns.md`](https://github.com/cathrynlavery/diagram-design/blob/main/semantic-patterns.md).

### Where is the routing validation tested?

The [`scripts/verify-semantic-motion.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/verify-semantic-motion.py) script parses [`SKILL.md`](https://github.com/cathrynlavery/diagram-design/blob/main/SKILL.md) and cross-references every pattern-to-type link against the authoritative routing table. This catches documentation drift—when a pattern's mapping changes in code but [`SKILL.md`](https://github.com/cathrynlavery/diagram-design/blob/main/SKILL.md) retains stale references.