blue/.blue/docs/rfcs/0043-mermaid-diagram-standards.accepted.md
Eric Garcia 006546b2fd feat: RFC 0043 Mermaid diagram standards
Establishes mandatory standards for Mermaid diagrams in Blue documents:
- Neutral theme required for dark/light mode compatibility
- Leaf node counting for LR flow warnings (>3 nodes)
- Plain text for architecture labels (no emoji color injection)
- Shape semantics advisory for new diagrams
- Auto-fix for theme declaration only (colors require manual review)

Includes alignment dialogue with 10/10 tensions resolved across 3 rounds.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 11:58:32 -05:00

9.1 KiB

RFC 0043: Mermaid Diagram Standards for Blue Documents

Status Accepted
Created 2026-01-30
Spike 2026-01-30T1521Z-mermaid-diagram-style-guide
Dialogue 2026-01-30T1730Z-rfc-0043-mermaid-diagram-standards

Summary

Establish mandatory standards for Mermaid diagrams in all Blue-generated documents, ensuring readability in both light and dark modes through the neutral theme, vertical flow preference, and automated lint enforcement.


Problem

Mermaid diagrams in Blue documents have inconsistent styling that causes readability issues:

  1. Dark mode incompatibility — Custom fill colors (#e8f5e9, #e3f2fd) designed for light mode become unreadable in dark mode
  2. Invisible text — Dark nodes with no explicit text color disappear against dark backgrounds
  3. Subgraph label contrast — Colored subgraph backgrounds obscure labels
  4. Horizontal sprawlflowchart LR requires horizontal scrolling on narrow viewports
  5. No enforcement — Authors must remember style rules manually

This affects:

  • ADRs with architecture diagrams
  • RFCs with system designs
  • Dialogue recordings with flow visualizations
  • Any document Blue generates containing Mermaid

Proposal

1. Mandatory Theme Declaration

All Mermaid diagrams MUST begin with the neutral theme declaration:

%%{init: {'theme': 'neutral'}}%%
flowchart TB
    ...

2. Flow Direction Guidelines

Direction When to Use Enforcement
TB (top-to-bottom) Default for all diagrams
LR (left-to-right) Only when ≤3 leaf nodes Advisory warning

The constraint is horizontal space. LR with 4+ nodes forces horizontal scrolling on narrow viewports.

Node Counting: Count leaf nodes (terminal visual elements), not container subgraphs. A diagram with 2 subgraphs each containing 4 nodes counts as 8 nodes for threshold purposes.

3. Prohibited Styling

The following are NOT ALLOWED:

%% PROHIBITED
style NODE fill:#e8f5e9
style NODE fill:#any-color
classDef custom fill:#color

The neutral theme provides sufficient visual distinction through grayscale shading.

4. Emoji Guidance

Context Emoji Allowed Rationale
Architecture component labels No Platform-dependent color rendering undermines neutral theme
Subgraph titles No Same dark-mode readability issues as custom fills
Annotations/comments Yes Non-critical context where variance is acceptable

Example:

%% GOOD: Plain text architecture labels
subgraph SV["Superviber Control Plane"]
    ORCH["Orchestration"]
end

%% BAD: Emoji injects platform-dependent color
subgraph SV["☁️ Superviber Cloud"]

Advisory for new diagrams. Legacy documents exempt.

Shape Syntax Semantic
Rectangle [text] Services, components, processes
Rounded (text) User-facing elements, entry points
Database [(text)] Data stores, persistence
Stadium ([text]) External systems, third-party
Hexagon {{text}} Decision points, conditionals
Circle ((text)) Events, triggers

6. Edge Label Guidelines

Advisory, not prescriptive.

  • Recommended maximum: 15 characters
  • Use abbreviations: mTLS, gRPC, REST
  • Longer labels acceptable when clarity requires it

7. Lint Rule Enforcement

Extend crates/blue-mcp/src/handlers/lint.rs (existing infrastructure):

/// Mermaid diagram linting for Blue documents
fn check_mermaid_blocks(content: &str) -> Vec<Diagnostic> {
    let mut diagnostics = vec![];

    for block in extract_mermaid_blocks(content) {
        // REQUIRED: Neutral theme declaration
        if !block.contains("'theme': 'neutral'")
           && !block.contains("\"theme\": \"neutral\"") {
            diagnostics.push(Diagnostic {
                severity: Severity::Error,
                message: "Mermaid diagram must use neutral theme".into(),
                suggestion: Some("Add: %%{init: {'theme': 'neutral'}}%%".into()),
                auto_fix: Some(AutoFix::PrependLine(
                    "%%{init: {'theme': 'neutral'}}%%".into()
                )),
            });
        }

        // PROHIBITED: Custom fill colors (NO auto-fix - preserves semantic intent)
        if block.contains("fill:#") || block.contains("fill: #") {
            diagnostics.push(Diagnostic {
                severity: Severity::Error,
                message: "Custom fill colors prohibited in Mermaid diagrams".into(),
                suggestion: Some("Remove style directives manually; review semantic intent".into()),
                auto_fix: None, // Intentionally no auto-fix
            });
        }

        // ADVISORY: LR flow with >3 leaf nodes
        if block.contains("flowchart LR") || block.contains("graph LR") {
            let leaf_count = count_leaf_nodes(&block);
            if leaf_count > 3 {
                diagnostics.push(Diagnostic {
                    severity: Severity::Warning,
                    message: format!(
                        "LR flow with {} leaf nodes may cause horizontal scrolling",
                        leaf_count
                    ),
                    suggestion: Some("Consider flowchart TB for better viewport fit".into()),
                    auto_fix: None,
                });
            }
        }
    }

    diagnostics
}

/// Count leaf nodes (terminal visual elements, not container subgraphs)
fn count_leaf_nodes(mermaid_content: &str) -> usize {
    // Count node definitions: ID[label], ID(label), ID[(label)], etc.
    // Exclude: subgraph, end, style, classDef, linkStyle
    let node_pattern = regex::Regex::new(r"^\s*(\w+)\s*[\[\(\{\<]").unwrap();
    let exclude_keywords = ["subgraph", "end", "style", "classDef", "linkStyle"];

    mermaid_content
        .lines()
        .filter(|line| {
            let trimmed = line.trim();
            !exclude_keywords.iter().any(|kw| trimmed.starts_with(kw))
                && node_pattern.is_match(trimmed)
        })
        .count()
}

8. Template Integration

Update Blue's document templates to generate compliant Mermaid by default:

fn generate_mermaid_block(diagram_type: &str, content: &str) -> String {
    format!(
        "```mermaid\n%%{{init: {{'theme': 'neutral'}}}}%%\n{} TB\n{}\n```",
        diagram_type,
        content
    )
}

Migration

Auto-Fix Scope

Issue Auto-Fix Rationale
Missing theme declaration ✓ Yes Non-destructive prepend
Custom fill colors ✗ No Preserves semantic intent; requires manual review
LR with >3 nodes ✗ No Advisory only; architectural choice

Migration Process

  1. Run lint with --fix to auto-add theme declarations
  2. Manual review for custom colors (lint reports, human decides)
  3. Priority: ADRs > RFCs > Dialogues

Implementation Track

Templates and lint can proceed in parallel:

  • Templates: Generate compliant diagrams for new documents
  • Lint: Flag violations in existing documents (warning-only mode during transition)

Alternatives Considered

A. dark Theme Only

Rejected: Looks poor in light mode. We need both-mode compatibility.

B. base Theme with Custom Variables

Rejected: Requires verbose themeVariables block in every diagram. High maintenance burden.

C. Pre-render to SVG at Build Time

Rejected: Loses live preview in editors. Adds build complexity.

D. Documentation Only (No Enforcement)

Rejected: Relies on authors remembering. Inconsistency will creep back.

E. New blue_lint Crate

Rejected: Existing lint infrastructure in crates/blue-mcp/src/handlers/lint.rs already handles RFC docs. Extend, don't duplicate.


Success Criteria

  1. All Mermaid diagrams pass blue_lint without errors
  2. Diagrams readable in VS Code light theme, VS Code dark theme, GitHub light, GitHub dark
  3. No custom fill:# directives in any Blue document
  4. Template generates compliant diagrams by default
  5. Lint runs in parallel with template development

References


Tasks

  • Extend lint.rs with Mermaid block extraction
  • Implement theme declaration check with auto-fix
  • Implement fill color check (error, no auto-fix)
  • Implement leaf node counting for LR warning
  • Update document generation templates
  • Migrate existing diagrams in ADRs (manual color review)
  • Migrate existing diagrams in RFCs (manual color review)
  • Add Mermaid cheatsheet to .blue/docs/