Skip to content

feat: add Cynefin framework diagram type#7535

Merged
knsv merged 22 commits into
mermaid-js:developfrom
ragelink:feature/cynefin-diagram
May 6, 2026
Merged

feat: add Cynefin framework diagram type#7535
knsv merged 22 commits into
mermaid-js:developfrom
ragelink:feature/cynefin-diagram

Conversation

@ragelink
Copy link
Copy Markdown
Contributor

@ragelink ragelink commented Mar 27, 2026

Summary

Adds a Cynefin framework diagram type to mermaid. The Cynefin framework (created by Dave Snowden) is a decision-making framework that categorizes problems into five complexity domains, widely used in agile, incident management, strategy, and organizational design.

There is currently no standard text-based DSL for Cynefin diagrams anywhere. This is a first.

Ref: #7534

Syntax

cynefin-beta
  title Incident Response

  complex
    "Investigate root cause"
    "Run chaos experiment"

  complicated
    "Analyze performance data"

  clear
    "Restart service"
    "Apply known fix"

  chaotic
    "Page on-call immediately"

  confusion
    "Unknown failure mode"

  complex --> complicated : "Pattern identified"
  clear --> chaotic : "Complacency"

Features

  • Five fixed domains in canonical layout (Complex top-left, Complicated top-right, Chaotic bottom-left, Clear bottom-right, Confusion center)
  • Wavy organic boundaries between domains (SVG cubic bezier curves with deterministic seeded PRNG)
  • The "cliff" between Clear and Chaotic (thicker, darker boundary)
  • Confusion/Disorder center ellipse overlay
  • Domain metadata: decision model subtitles (Probe/Sense/Respond, etc.) and practice types (Emergent, Good, Best, Novel)
  • Items placed as text badges within each domain
  • Transition arrows between domains with optional labels (curved quadratic bezier paths)
  • Full theme integration across all 5 mermaid themes (default, dark, forest, neutral, base)
  • Schema-driven config: width, height, padding, showDomainDescriptions, boundaryAmplitude
  • Accessibility: ARIA roles, labels, descriptions

Architecture

  • Langium grammar with domain blocks, items, and transitions
  • Follows the radar diagram pattern (module-level state, schema defaults, no fallbacks)
  • Boundary path generators in dedicated module (cynefinBoundaries.ts)
  • Scoped SVG marker IDs for multi-diagram pages

Test plan

  • pnpm run build passes with 0 errors
  • Full test suite: 3,796 tests pass, 0 failures, 0 regressions
  • Multi-diagram ID uniqueness test includes cynefin
  • Examples test includes cynefin
  • Visual verification of 4 test diagrams in browser (basic items, transitions, empty domains, many items)
  • Cypress e2e (cypress/integration/rendering/cynefin.spec.js)
  • Cynefin-specific unit tests (cynefin.spec.ts) and integration tests (cynefin.integration.spec.ts)

Closes #7534

Add a Cynefin framework diagram type for categorizing problems by
complexity domain. Five fixed domains (Complex, Complicated, Clear,
Chaotic, Confusion) with wavy organic boundaries, items placed within
domains, and transition arrows between them.

Features:
- Langium grammar with domain blocks, items, and transitions
- Wavy SVG bezier boundaries (deterministic via seeded PRNG)
- The "cliff" between Clear and Chaotic
- Domain labels with decision model and practice type subtitles
- Item badges stacked within each domain
- Curved transition arrows with optional labels
- Full theme integration (5 themes with domain-specific colors)
- Schema-driven config (width, height, padding, boundaryAmplitude)
- Accessibility (ARIA roles, labels)

Ref: mermaid-js#7534
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 27, 2026

🦋 Changeset detected

Latest commit: 48d65d0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
mermaid Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify
Copy link
Copy Markdown

netlify Bot commented Mar 27, 2026

Deploy Preview for mermaid-js ready!

Name Link
🔨 Latest commit 48d65d0
🔍 Latest deploy log https://app.netlify.com/projects/mermaid-js/deploys/69fa36e854b7200008971949
😎 Deploy Preview https://deploy-preview-7535--mermaid-js.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added the Type: Enhancement New feature or request label Mar 27, 2026
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Mar 27, 2026

Open in StackBlitz

@mermaid-js/examples

npm i https://pkg.pr.new/@mermaid-js/examples@7535

mermaid

npm i https://pkg.pr.new/mermaid@7535

@mermaid-js/layout-elk

npm i https://pkg.pr.new/@mermaid-js/layout-elk@7535

@mermaid-js/layout-tidy-tree

npm i https://pkg.pr.new/@mermaid-js/layout-tidy-tree@7535

@mermaid-js/mermaid-zenuml

npm i https://pkg.pr.new/@mermaid-js/mermaid-zenuml@7535

@mermaid-js/parser

npm i https://pkg.pr.new/@mermaid-js/parser@7535

@mermaid-js/tiny

npm i https://pkg.pr.new/@mermaid-js/tiny@7535

commit: 48d65d0

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 27, 2026

Codecov Report

❌ Patch coverage is 4.26743% with 673 lines in your changes missing coverage. Please review.
✅ Project coverage is 3.32%. Comparing base (71f9731) to head (48d65d0).

Files with missing lines Patch % Lines
...es/mermaid/src/diagrams/cynefin/cynefinRenderer.ts 0.31% 319 Missing ⚠️
.../mermaid/src/diagrams/cynefin/cynefinBoundaries.ts 1.03% 96 Missing ⚠️
packages/mermaid/src/diagrams/cynefin/cynefinDb.ts 1.44% 68 Missing ⚠️
packages/mermaid/src/diagrams/cynefin/styles.ts 2.85% 34 Missing ⚠️
packages/parser/src/language/cynefin/module.ts 4.76% 20 Missing ⚠️
packages/mermaid/src/themes/theme-base.js 0.00% 18 Missing ⚠️
packages/mermaid/src/themes/theme-dark.js 0.00% 18 Missing ⚠️
packages/mermaid/src/themes/theme-forest.js 0.00% 18 Missing ⚠️
packages/mermaid/src/themes/theme-neutral.js 0.00% 18 Missing ⚠️
...ages/mermaid/src/diagrams/cynefin/cynefinParser.ts 6.25% 15 Missing ⚠️
... and 11 more
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           develop   #7535      +/-   ##
==========================================
+ Coverage     3.31%   3.32%   +0.01%     
==========================================
  Files          543     555      +12     
  Lines        57217   57919     +702     
  Branches       840     867      +27     
==========================================
+ Hits          1898    1928      +30     
- Misses       55319   55991     +672     
Flag Coverage Δ
unit 3.32% <4.26%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/mermaid/src/config.type.ts 100.00% <ø> (ø)
packages/mermaid/src/defaultConfig.ts 44.69% <100.00%> (+0.49%) ⬆️
packages/mermaid/src/diagrams/cynefin/types.ts 100.00% <100.00%> (ø)
packages/mermaid/src/themes/theme-default.js 95.86% <100.00%> (+0.16%) ⬆️
.build/jsonSchema.ts 0.00% <0.00%> (ø)
packages/mermaid/src/docs/.vitepress/config.ts 0.39% <0.00%> (-0.01%) ⬇️
packages/parser/src/language/cynefin/index.ts 0.00% <0.00%> (ø)
packages/parser/src/language/index.ts 0.00% <0.00%> (ø)
packages/examples/src/index.ts 1.72% <0.00%> (-0.07%) ⬇️
...s/mermaid/src/diagram-api/diagram-orchestration.ts 0.00% <0.00%> (ø)
... and 15 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- 19 unit tests: DB operations, boundary path generators, PRNG determinism
- 13 integration tests: full parse-to-db pipeline for domains, items,
  transitions, accessibility, complex diagrams, re-parse after clear
Copy link
Copy Markdown
Collaborator

@knsv-bot knsv-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[sisyphus-bot]

Review: feat: add Cynefin framework diagram type

Hey @ragelink — first off, thanks for taking this on. A text-based DSL for Cynefin is a genuinely novel contribution, and the amount of thought that went into the domain modeling (wavy boundaries, the cliff, confusion overlay, deterministic PRNG) is impressive. Sorry this sat without review for almost two weeks — let's get this across the finish line.

This is a substantial, well-structured PR. There are a few blocking items that need addressing before merge, but the architecture is sound and the path forward is clear. They are mostly admin pieces but for us they are important to keep the flow going.


What's working well

🎉 [praise] Langium grammar — correct choice for new diagrams, and the grammar is clean and expressive. The DOMAIN_NAME terminal constraining valid domain names at the grammar level is a smart design choice.

🎉 [praise] Deterministic boundary rendering — The seeded PRNG (cynefinBoundaries.ts) ensures reproducible wavy boundaries while still looking organic. Well-tested with proper determinism assertions.

🎉 [praise] Comprehensive test coverage for a first pass — DB unit tests, boundary path tests, full integration parsing tests (basic, transitions, accessibility, complex diagrams, clear-and-reparse), and multi-diagram ID uniqueness coverage. Strong foundation.

🎉 [praise] Clean diagram architecture — follows the radar/wardley pattern nicely: parser → db → renderer pipeline, proper clear() reset, Langium module registration, lazy-loaded detector. No cross-diagram imports.

🎉 [praise] Security — All user text inserted via D3's .text() (safe text nodes), no .html()/innerHTML, no string interpolation into SVG markup, Langium grammar constrains input. DOMPurify pipeline is intact. Clean bill of health.


Blocking items

🔴 [blocking] Missing Langium generated files
The Cynefin grammar is added to langium-config.json and module.ts imports CynefinGrammarGeneratedModule from ../generated/module.js, but the generated files in packages/parser/src/language/generated/ were not regenerated. The index.ts exports (Cynefin, isCynefin, isDomainBlock, isDomainItem, isTransition, CynefinGrammarGeneratedModule) don't exist in the current generated code. Please run:

pnpm --filter parser langium:generate

and commit the regenerated files.

🔴 [blocking] Missing Cypress e2e visual regression tests
The parser/DB coverage is solid. But new diagram types require visual regression tests in cypress/integration/rendering/ using the imgSnapshotTest() helper. This is one of the project's most important quality safeguards — it catches rendering regressions across themes and configurations. The test page (test-cynefin.html) already has 4 great test scenarios that could be adapted directly. Reference: any existing e2e test like cypress/integration/rendering/radar.spec.js.

🔴 [blocking] Missing changeset
No changeset file is included. For a new feature:

pnpm changeset
# Select: packages/mermaid, minor bump
# Message: feat: add Cynefin framework diagram type

Important items

🟡 [important] Renderer ignores config values
The config schema defines width, height, padding, showDomainDescriptions, and boundaryAmplitude — but the renderer hardcodes width = 800, height = 600, padding = 40 at cynefinRenderer.ts:72-74 and never reads from db.getConfig(). The showDomainDescriptions and boundaryAmplitude settings have no effect. It would be great to wire these up so users can actually configure the diagram.

🟡 [important] Renderer uses hardcoded colors instead of theme variables
cynefinRenderer.ts:55-61 defines DOMAIN_COLORS with hardcoded hex values, and item badges at lines 207-215 use hardcoded #ffffff, #cccccc, #333333. Meanwhile, all 5 theme files define cynefin-specific variables (complexBg, complicatedBg, chaoticBg, clearBg, confusionBg, textColor, labelColor) — but these are never consumed by the renderer or styles.ts. This means switching themes won't actually change domain colors. Worth wiring the theme variables through so the diagram respects theme selection.

🟡 [important] Missing documentation
New diagram types need docs in packages/mermaid/src/docs/. Use MERMAID_RELEASE_VERSION as the version placeholder in any "Available since" references. The syntax examples in the PR body and test-cynefin.html are a great starting point.

🟡 [important] test-cynefin.html committed to package root
packages/mermaid/test-cynefin.html looks like a development/debugging file. It uses securityLevel: 'loose' and imports from ./dist/. This probably shouldn't be committed — consider removing it or moving the test scenarios into the Cypress e2e tests instead.


Nits and suggestions

🟢 [nit] cynefinDb.ts:31,46setDomains(blocks: any[]) and setTransitions(transitions: any[]) use any[]. Consider using the Langium-generated AST types for stronger type safety.

💡 [suggestion] Handdrawn/rough mode — Not a blocker, but it would be good to explicitly note whether handdrawn mode is supported or not. If it can't be supported yet, a brief mention in the docs is sufficient so users know.

💡 [suggestion] config.type.ts regeneration — The changes to config.type.ts look correct and properly generated from the schema. Just double-check you ran pnpm run --filter mermaid types:build-config rather than editing manually — CI will verify this.


Self-check

  • At least one 🎉 praise item (5 total)
  • No duplicate comments
  • Severity tally: 3 🔴 / 4 🟡 / 1 🟢 / 2 💡 / 5 🎉
  • Verdict matches criteria: REQUEST_CHANGES (3 🔴 blocking)
  • Not a draft PR
  • Tone check: constructive and appreciative ✅

@ragelink
Copy link
Copy Markdown
Contributor Author

Thank you for the thoughtful reply and consideration. I've been a longtime fan of mermaid and have been eager to contribute for a while. I even tried another PR for Wardley Maps (another diagramming construct I find very useful, but I was a bit late on that one: ragelink#1).

I'm looking forward to helping out and eager for feedback, so please let me know if there's anything else I can do to make this more valuable to the community.

@ragelink
Copy link
Copy Markdown
Contributor Author

Quick update: I'm working on the review items now. Should have an updated push soon with the changeset, e2e tests, config and theme wiring, docs, and the rest. Thanks for your patience!

Review items addressed:

- Add changeset for the cynefin feature (minor bump)
- Add Cypress e2e visual regression tests covering basic, transitions,
  empty domains, many items, config overrides, theme overrides, zero
  amplitude, and accessibility
- Wire all config values into the renderer (width, height, padding,
  showDomainDescriptions, boundaryAmplitude); these now flow from the
  schema through db.getConfig() at render time
- Wire theme variables into the renderer for all colors (domain
  backgrounds, boundaries, cliff, arrows, text); item badges now use
  per-domain colors instead of hardcoded values
- Pass boundaryAmplitude to the boundary path generators so users can
  control or disable waviness
- Replace any[] with proper Langium AST types (DomainBlock, Transition)
  in cynefinDb.ts and the unit test helpers
- Type getConfig() return as Required<CynefinDiagramConfig>
- Add comprehensive syntax documentation at src/docs/syntax/cynefin.md
  with examples, config table, theme variable table, and accessibility
  notes
- Add cynefin to the vitepress sidebar
- Remove the dev-only test-cynefin.html file from the package root
@argos-ci
Copy link
Copy Markdown

argos-ci Bot commented Apr 10, 2026

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
default (Inspect) 👍 Changes approved 1 changed, 11 added May 5, 2026, 6:41 PM

@ragelink
Copy link
Copy Markdown
Contributor Author

ragelink commented Apr 10, 2026

Pushed an update addressing the rest of the feedback.

One note on the generated files item: packages/parser/src/language/generated/ is gitignored project-wide (.gitignore line 61) and CI regenerates it via pnpm prepare. I think none of the other diagram types commit generated files either, so I left it alone. I verified a clean build from scratch produces the right types.

Happy to commit them if you'd prefer that for this PR, just let me know.

Everything else is in:

  • Changeset added (minor bump)
  • Cypress e2e tests with 9 imgSnapshotTest scenarios
  • Renderer now reads width, height, padding, showDomainDescriptions, and boundaryAmplitude from db.getConfig() at render time
  • All hardcoded colors replaced with theme variables; item badges now pick up their domain color
  • Full syntax docs at src/docs/syntax/cynefin.md, sidebar updated
  • test-cynefin.html removed
  • any[] replaced with DomainBlock[] and Transition[]
  • Handdrawn mode noted as not currently supported

@ragelink ragelink requested a review from knsv-bot April 10, 2026 23:17
Copy link
Copy Markdown
Collaborator

@ashishjain0512 ashishjain0512 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[sisyphus-bot]

Thanks for tackling this, @ragelink — and especially for the substantial follow-up work in commit ea1c48f that addressed prior review items (changeset added, Cypress e2e tests written, schema config wired through to the renderer, theme variables threaded across all five themes, dev test file removed, any[] replaced with proper Langium AST types, comprehensive syntax docs added). That kind of responsiveness on a large feature is exactly what makes new diagram types land. This PR is close to ready — most of what's below is final polish and a few correctness edges to tighten before flipping it on.

I'm doing a full New Diagram Type review per the project's contributor checklist, so this is structured rather than narrative. Good news first.


What's working well

🎉 Langium-first. cynefin.langium is the right choice for a new diagram (no JISON), and the grammar is concise and readable. The fixed DOMAIN_NAME terminal is a smart constraint — it prevents typos at parse time and gives the renderer a closed enum to switch on.

🎉 Plugin contract is complete. cynefinDetector.ts (id + detector + loader), cynefinDiagram.ts (parser + db + renderer + styles), cynefinDb.ts, cynefinParser.ts, cynefinRenderer.ts, styles.ts, types.ts — every piece is present and registered in diagram-orchestration.ts:32-115. Examples wired in (packages/examples/src/index.ts), cspell entry added, langium-config entry added, parser exports + parse-dispatcher added in packages/parser/src/parse.ts. Nothing missed in the wiring.

🎉 Excellent test coverage. 19 unit tests for DB/PRNG/path generators in cynefin.spec.ts, 13 integration tests covering parse-to-DB pipeline (basic, transitions, accessibility, complex, re-parse-after-clear) in cynefin.integration.spec.ts, and 8 Cypress visual regression scenarios in cypress/integration/rendering/cynefin.spec.js (basic, transitions, empty, many items, config override, theme override, zero amplitude, accessibility). The Cypress coverage is exactly what the project asks for on new diagrams.

🎉 Theme integration across all five themes. theme-base.js, theme-dark.js, theme-default.js, theme-forest.js, theme-neutral.js each define a complete cynefin block with domain backgrounds, cliff color, boundary color, and font sizes. Color choices visibly reflect each theme's palette (forest has earth tones, dark has saturated brights). This is the part new diagrams most often skimp on, and you didn't.

🎉 Schema-driven config done right. New optional CynefinDiagramConfig in config.schema.yaml with width, height, padding, showDomainDescriptions, boundaryAmplitude. All optional with sensible defaults — non-breaking. Properly threaded through db.getConfig() → renderer at cynefinRenderer.ts:84-93. The Cypress test at cynefin.spec.js:78-87 actually exercises the config override path. Beautiful.

🎉 Determinism via seeded PRNG. seededRandom (mulberry32) + hashString(id) means the wavy boundaries are stable per diagram id. Critical for visual snapshot testing — and the cynefin.spec.ts tests assert the determinism explicitly. Smart.

🎉 Comprehensive docs. packages/mermaid/src/docs/syntax/cynefin.md is 213 lines including conceptual intro, syntax reference, transition examples, configuration table, theme-variable table, accessibility section, and MERMAID_RELEASE_VERSION placeholder usage. Linked sidebar entry added.


Things to address

🟡 [important] — Self-loop transitions produce NaN coordinates

packages/mermaid/src/diagrams/cynefin/cynefinRenderer.ts:326-356

The grammar allows complex --> complex (the Transition rule has no constraint that from and to differ). When that happens, the renderer computes:

const dx = x2 - x1;       // 0
const dy = y2 - y1;       // 0
const len = Math.sqrt(dx * dx + dy * dy);  // 0
const nx = -dy / len;     // NaN
const ny = dx / len;      // NaN
const cpx = mx + nx * offsetAmount - padding;  // NaN
const cpy = my + ny * offsetAmount - padding;  // NaN

The resulting path string M{cx},{cy} Q{NaN},{NaN} {cx},{cy} will silently fail or render an invisible path in most browsers, and the optional label gets placed at NaN. Since users could plausibly draw "self-reflection" transitions on the canonical Cynefin diagram, this is worth a defensive guard. Either:

  1. Reject self-loops at the grammar/DB level with a helpful error, or
  2. In the renderer, special-case len === 0 to either skip the transition or draw a small loopback arc above the domain center.

Whichever fits the conceptual model of the diagram better. Test case for either approach should join the integration suite.


🟡 [important] — Item badge width estimated heuristically; will misalign with real labels

packages/mermaid/src/diagrams/cynefin/cynefinRenderer.ts:276

const textLen = item.label.length * 7 + itemPaddingX * 2;

The 7-pixels-per-character estimate is a rough average — fine for short ASCII strings, but it will produce visibly wrong badge widths for:

  • Wide characters (W, M, asian glyphs)
  • Narrow characters (i, l)
  • Different fonts / font sizes (the badge font is configurable via theme)
  • Strings shorter than ~3 chars (badges become awkwardly small)

The standard Mermaid pattern is to render the text first, call getBBox() to measure, then size the wrapping rect. See journeyRenderer.js or pieRenderer.ts for examples — the helper renders text invisibly, measures it, then positions the background rect around the measured bounds. Worth investing in the getBBox approach now since item badges are the most prominent UI element of the diagram and contributors will copy this pattern.


🟡 [important] — Confusion domain item placement spills outside the visible ellipse

packages/mermaid/src/diagrams/cynefin/cynefinRenderer.ts:171-181, 264-303

The confusion ellipse is sized to roughly 10% of width × 10% of height (confusionRx = width * 0.1, confusionRy = height * 0.1 — at the default 800×600, that's an 80×60 ellipse). But items placed in the confusion domain start at layout.cy + (showDomainDescriptions ? 25 : 15) and stack downward at 30px per badge — meaning even one item will extend below the ellipse, and any more than that will appear floating in dead space at the diagram's center.

A few directions to consider:

  1. Use a larger confusion region (the canonical Cynefin diagram has confusion as a real central area, not a small overlay)
  2. Constrain the confusion-domain item count visually (collapse to "+N more" or similar)
  3. Render confusion items differently (e.g., as a stacked list outside the ellipse with a connector)

Whichever direction fits the design intent — the current behavior will look broken with realistic content (and the empty-domain Cypress test passes precisely because no confusion items are placed).


🟡 [important] — Inline .attr() styling duplicates the styles.ts CSS

packages/mermaid/src/diagrams/cynefin/cynefinRenderer.ts:135-181, 220-242, 281-301, 351-374 and styles.ts:1-104

The renderer applies presentation via D3 attribute calls (.attr('fill', ...), .attr('stroke', ...), .attr('font-size', ...), etc.) and the diagram ships a styles.ts that emits CSS for selectors like .cynefinDomainLabel, .cynefinSubtitle, .cynefinItem text, .cynefinArrowLine, etc. The CSS is largely shadowed by the inline attributes — for example, .cynefinDomainLabel { fill: ... } in styles.ts is overridden by the .attr('fill', theme.labelColor) inline at cynefinRenderer.ts:196.

This double-styling makes future theme changes confusing (which one wins? where do I edit?). Pick one model:

  • CSS classes only (preferred — matches the rest of the codebase): keep styles.ts, drop the inline .attr('fill', ...) / .attr('font-size', ...) calls, and let the CSS handle presentation. Reference: journey/styles.js, pie/styles.ts.
  • Inline attrs only: drop styles.ts entirely. Less consistent with the project but simpler. Not recommended.

Going with CSS classes also makes the diagram play more nicely with user CSS overrides (which is a documented Mermaid extension point).


🟡 [important] — Handdrawn / rough mode not addressed

The New Diagram Type checklist asks that handdrawn mode either be implemented or explicitly documented as unavailable. The cynefin docs (packages/mermaid/src/docs/syntax/cynefin.md) don't mention rough mode. Given the wavy organic boundaries are already a "handdrawn-feeling" aesthetic, this might be a case where the diagram is implicitly handdrawn-only — but that should be made explicit in the docs (one-liner stating handdrawn mode is not separately supported, with a brief reason).

Per the checklist this is "not a hard blocker for merging" but does need explicit acknowledgement.


🟢 [nit] — aria-label on root SVG vs <title> element

packages/mermaid/src/diagrams/cynefin/cynefinRenderer.ts:111-113

Other Mermaid diagrams typically attach accessibility text via <title> and <desc> SVG child elements (the W3C recommendation for SVG accessibility). The cynefin renderer uses aria-label for the title and <desc> for the description — half and half. Consider switching the title to a <title> child element for consistency with diagrams like pieRenderer.ts. Not a security or functional issue (the XSS sub-agent confirmed accTitle is pre-sanitized via sanitizeText in commonDb.ts), just consistency.


🟢 [nit] — Grammar entry rule has three alternatives for the type marker

packages/parser/src/language/cynefin/cynefin.langium:5

('cynefin-beta' | 'cynefin-beta:' | 'cynefin-beta' ':')

The third alternative ('cynefin-beta' ':') accepts cynefin-beta : with a space before the colon. Three alternatives for a type marker is unusual — most diagrams accept only the bare token. If both cynefin-beta and cynefin-beta: need support, two alternatives should suffice. Worth a short comment in the grammar explaining the intent, or simplifying to one form (other Langium-based diagrams like radar and treemap use just the bare keyword).


🟢 [nit] — Detector regex has no end boundary

packages/mermaid/src/diagrams/cynefin/cynefinDetector.ts:10

return /^\s*cynefin-beta/.test(txt);

Would also match cynefin-betaXYZ or cynefin-beta-extension. Other diagram detectors have the same quirk so this is consistent, but a \b word boundary or (?:\s|$) lookahead would be more precise. Take it or leave it.


🟢 [nit] — getCynefinTheme casts via any

packages/mermaid/src/diagrams/cynefin/cynefinRenderer.ts:53-75

return (themeVariables as any).cynefin as { /* ... */ };

The shape is locally typed (good), but the any cast loses the connection to the theme system. If you can extend the MermaidThemeVariables interface with an optional cynefin?: CynefinThemeVariables field, you'd avoid the cast. Existing diagrams (e.g., radar, venn) augment the theme typings — worth following that pattern.


💡 [suggestion] — Use Resolves #7534 instead of Ref: #7534 in the PR description

GitHub auto-closes the linked issue when the PR merges if you use Resolves/Closes/Fixes. With Ref: someone has to close it manually. Tiny thing.


💡 [suggestion] — Item overflow handling

Long item labels or many items per domain will overflow the domain bounds. Consider word-wrapping, text truncation with ellipsis, or scaling. Not blocking — first beta is allowed to be opinionated about content fitting — but worth a TODO comment or follow-up issue so it doesn't get lost.


💡 [suggestion] — Constraint: transitions to/from confusion

Architecturally, "confusion" represents not knowing which domain an item belongs to, so transitions like complex --> confusion are conceptually questionable (the canonical model has items move OUT of confusion, not into it). Worth a sentence in the docs about which transitions are conceptually meaningful, or constraining the grammar to allow only confusion --> X. Doesn't have to be done now.


Security

No XSS or injection issues identified. The XSS sub-agent reviewed all 12 changed files in the cynefin diagram + parser. All user-controlled text (item.label, transition.label, title, accDescription) flows through D3's .text() method (text-node creation, not HTML parsing). accTitle is set via .attr('aria-label', ...) after pre-sanitization in commonDb. No innerHTML, .html(), eval, Function(), foreignObject, event handlers, <script>, or javascript: URIs introduced. The styles.ts CSS interpolation follows the same pattern as existing diagrams — pre-existing accepted approach, not a new attack surface. The diagram does not bypass the standard mermaidAPI render pipeline, so DOMPurify sanitization still applies to final SVG output.


Verdict

Requesting changes for the 4 🟡 items in aggregate (each individually borderline, but together they shape the visual quality and correctness of the diagram's first beta). The handdrawn-mode acknowledgement is the cheapest fix; the confusion-overflow and self-loop NaN are the most user-visible. Once those land, this should be in great shape for the first text-based Cynefin DSL anywhere.

Genuinely impressive scope for a single PR — Langium grammar + renderer + 5 themes + schema + 40 tests + comprehensive docs. Looking forward to the next iteration.


Self-check

  • 🔴 blocking: 0
  • 🟡 important: 4
  • 🟢 nit: 4
  • 💡 suggestion: 3
  • 🎉 praise: 6

@ragelink ragelink requested a review from ashishjain0512 April 15, 2026 20:46
@knsv-bot
Copy link
Copy Markdown
Collaborator

[sisyphus-bot]

Hey @ragelink — thanks again for the follow-up work in ea1c48f. That commit cleanly resolved the Round 1 items (changeset, Cypress e2e, schema config wired through, theme variables threaded, docs, dev HTML removed, proper AST types). Great response to the first pass.

Before going further: I want to flag a discrepancy so we can untangle it. The comment above from @smd-lm describes a set of fixes (self-loop rejection in setTransitions, getBBox() badge measurement, MAX_CONFUSION_ITEMS = 3 overflow, CSS-classes-only refactor, detector regex change, grammar 3rd-alternative removal, aria-label<title>, dropping the as any cast). I checked each one against the current HEAD (1bb40121) and none of them appear to be in the code — cynefinDb.ts, cynefinRenderer.ts, styles.ts, cynefinDetector.ts, and cynefin.langium all match the ea1c48f state. And I don't see any commits from smd-lm on this branch.

Could be a branch that hasn't been pushed, a sync glitch, or just crossed wires — could you confirm what's intended to be in this PR? Happy to re-review once the branch reflects the fixes.

For clarity, here are the Round 2 items from the prior review that still look outstanding against the current HEAD:

🟡 Self-loop transitions produce NaNcynefinRenderer.ts:343-349. complex --> complex still results in len = 0 and NaN control points. Either reject at the DB/grammar level or special-case len === 0.

🟡 Badge width heuristiccynefinRenderer.ts:276. item.label.length * 7 misaligns on non-monospace fonts and non-ASCII. A getBBox()-based measurement (with a character-count fallback for SSR) would be more robust.

🟡 Confusion domain overflowcynefinRenderer.ts:171-172, 272-302. Radii at 0.1 don't fit item badges; items spill outside the ellipse on 3+ items. Worth widening the ellipse or capping items with an overflow indicator.

🟡 Inline attrs duplicating CSS classescynefinRenderer.ts:194-197, 281-302, 386-391 set font-size/font-weight/fill/stroke inline while styles.ts also defines them via class rules. Inline attrs win the cascade, so the CSS rules have no effect. Worth picking one model.

🟢 styles.ts uses generic theme varsstyles.ts:31,39,40,41,62,67,78,103. The five theme files now define a full cynefin block (complexBg, boundaryColor, labelColor, etc.) but styles.ts still reads themeVariables.primaryTextColor, lineColor, mainBkg, border1. Switching themes won't pick up the cynefin-specific overrides.

🟢 as any castcynefinRenderer.ts:57-58. Now that config.schema.yaml declares cynefin under theme variables, the cast could be replaced with a properly typed accessor.

🟢 Detector regexcynefinDetector.ts:10. ^\s*cynefin-beta will match cynefin-betanese or similar. Anchoring on (?:[\s:]|$) would be safer.

No hurry — just let us know what's going on with the branch state and we'll take it from there. Really do want to land this one.

@ragelink
Copy link
Copy Markdown
Contributor Author

ragelink commented Apr 16, 2026

Addressed all review feedback — here's a rundown of what changed:

🟡 Self-loop NaN (cynefinDb.ts + cynefinRenderer.ts)

Self-loops are now rejected at the DB level in setTransitions() with a log.warn. The renderer also has a defensive guard. Added 4 new tests (2 unit, 2 integration) covering mixed and all-self-loop inputs.

🟡 Badge width via getBBox() (cynefinRenderer.ts)

Replaced item.label.length * 7 heuristic with actual SVG text measurement. Text is appended first, getBBox() is called on the DOM node to get the real rendered width, then the rect is inserted behind it using g.insert('rect', 'text'). Falls back to the character-count estimate if getBBox is unavailable (e.g. server-side rendering).

🟡 Confusion domain overflow (cynefinRenderer.ts)

  • Ellipse radii increased from width*0.1 / height*0.1 to width*0.15 / height*0.15 — enough room for item badges at default size
  • Items now start at cy + labelOffset (instead of arbitrarily below center)
  • Capped at MAX_CONFUSION_ITEMS = 3; extra items render as a +N more overflow badge
  • Added Cypress test with 5 confusion items
  • Docs note added explaining the cap and its rationale

🟡 Inline attrs vs. CSS duplication (cynefinRenderer.ts + styles.ts)

Went with the CSS-classes-only model. The renderer now only sets structural/positional attrs and per-domain fill colors (which must be inline since they vary per domain). All font-size, font-weight, fill, stroke, and stroke-width attrs were removed from the renderer.

styles.ts was rewritten to read from the cynefin theme block directly (theme.labelColor, theme.boundaryColor, etc.) instead of the generic theme vars it was using before. Added missing rules: .cynefinConfusion stroke, .cynefinTitle, .cynefinItemText, .cynefinItemOverflow.

🟢 Nits

  • Detector regex: cynefin-betacynefin-beta(?:[\s:]|$)
  • Grammar: removed the 3rd alternative (space-before-colon form), added comment
  • Accessibility: aria-label<title> child element per W3C SVG recommendation
  • Removed the redundant as any cast in getCynefinTheme; narrowed return type to just the domain colors the renderer actually needs

Note: this comment was originally posted under a secondary account (@smd-lm) by mistake — reposted here under the correct account.

ragelink and others added 3 commits April 16, 2026 06:47
- Self-loop transitions now rejected in setTransitions() with log.warn; renderer has defensive guard
- Badge width uses getBBox() for accurate measurement, falls back to char-count heuristic for SSR
- Confusion domain radii increased to 0.15; items capped at MAX_CONFUSION_ITEMS=3 with +N more overflow badge
- Renderer switched to CSS-classes-only model; styles.ts reads from cynefin theme block directly
- Detector regex anchored with (?:[\s:]|$) to avoid false matches
- Grammar third alternative removed, comment added
- aria-label replaced with <title> child element per W3C SVG recommendation
- as any cast removed from getCynefinTheme
@ragelink
Copy link
Copy Markdown
Contributor Author

ragelink commented Apr 16, 2026

Sorry about the confusion on this one — the round 2 items were actually all addressed, I just forgot to push the commit. They've been sitting there locally this whole time. Also sorry for the earlier comment showing up from a secondary account (@smd-lm), that was me with the wrong GH credentials loaded. All cleaned up now and the branch is current.

@knsv
Copy link
Copy Markdown
Collaborator

knsv commented Apr 17, 2026

Sorry about the confusion on this one — the round 2 items were actually all addressed, I just forgot to push the commit. They've been sitting there locally this whole time. Also sorry for the earlier comment showing up from a secondary account (@smd-lm), that was me with the wrong GH credentials loaded. All cleaned up now and the branch is current.

No worries, I know exactly how it is. I have multiple as well: knsv, knsv-boty, and others. :)

We'll do another review then with the commit pushed !

Copy link
Copy Markdown
Collaborator

@knsv-bot knsv-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A word from @knsv. Great progress, just a few small things left. The diagrams look great!

[sisyphus-bot]

Thanks so much for this contribution, @ragelink — a first-of-its-kind text DSL for Cynefin is a lovely thing to land in Mermaid, and the quality of the work shows throughout. I went through the parser, renderer, boundaries, themes, schema, tests, and docs, plus a focused security pass. Great shape overall; a few small things below to iron out before merge.

🎉 What's working well

  • 🎉 Type-safe grammar. DOMAIN_NAME is restricted to the five canonical literals in packages/parser/src/language/cynefin/cynefin.langium, which means domain lookups in the renderer (domainBg[domainName], layouts[…]) are guaranteed safe by the parser. Elegant.
  • 🎉 Separation of concerns. Boundary path math lives in its own module (cynefinBoundaries.ts) with a deterministic seeded PRNG — reproducible output across renders and easy to unit-test.
  • 🎉 Defense in depth for self-loops. Filtered in cynefinDb.ts:setTransitions and also guarded in cynefinRenderer.ts inside the transition loop.
  • 🎉 Theme integration is thorough. All five themes (default/dark/forest/neutral/base) define a cynefin block with overridable domain colors, boundary/cliff widths, font sizes, etc. The dark and forest themes supply genuinely different palettes.
  • 🎉 Tests are solid. 162 lines of DB unit tests + 275 lines of parser integration tests + 10 Cypress visual cases (including config overrides, theme overrides, accessibility, straight vs wavy boundaries). This is well above the bar for a new diagram type.
  • 🎉 Multi-diagram uniqueness test updated. The entry in multi-diagram-id-uniqueness.spec.ts is exactly what we want for scoped marker IDs like cynefin-arrow-${id}.
  • 🎉 Changeset + MERMAID_RELEASE_VERSION placeholder in docs — followed the conventions precisely.
  • 🎉 Thoughtful UX touches. The overflow badge (+N more) when the confusion ellipse has more than MAX_CONFUSION_ITEMS, and the accessibility <title>/<desc> elements.

Security

I ran a focused XSS/injection review over the renderer, DB, parser, boundaries, and styles. No XSS or injection issues identified. All user-controlled text (item labels, transition labels, title, accTitle, accDescription, overflow badge) flows to D3's .text() (sets textContent, which HTML-escapes). No .html()/innerHTML, no foreignObject, no xlink:href/javascript: sinks, no DOMPurify config changes. Title/accTitle/accDescription additionally pass through sanitizeText upstream in commonDb.ts. The styles.ts CSS generator interpolates theme variables only, not diagram input.

Things to address

🟡 [important] useMaxWidth config is ignored

packages/mermaid/src/diagrams/cynefin/cynefinRenderer.ts passes true literally:

configureSvgSize(svg, totalHeight, totalWidth, true);

CynefinDiagramConfig extends BaseDiagramConfig, which supplies useMaxWidth, so users currently can't disable it. The radar renderer (which the PR notes as the reference pattern) reads from config — see packages/mermaid/src/diagrams/radar/renderer.ts:57:

configureSvgSize(svg, totalHeight, totalWidth, config.useMaxWidth ?? true);

Worth matching that so the config option actually works.

🟡 [important] Config key doesn't match the -beta keyword

The diagram is introduced via cynefin-beta at the syntax level, but the detector id and config key are cynefin (no -beta):

  • packages/mermaid/src/diagrams/cynefin/cynefinDetector.ts:7const id = 'cynefin';
  • packages/mermaid/src/schemas/config.schema.yamlcynefin: $ref: '#/$defs/CynefinDiagramConfig'
  • cynefinDb.ts reads commonGetConfig().cynefin

Compare to wardley-beta (the other -beta diagram in the codebase) — packages/mermaid/src/diagrams/wardley/wardleyDetector.ts:7 uses const id = 'wardley-beta'; and the schema key is wardley-beta:. The convention is: keyword == detector id == config/schema key.

Two concrete effects:

  1. A user writing %%{init: {"cynefin-beta": {...}}}%% (by analogy with wardley-beta) will silently get no config applied.
  2. When the -beta suffix is dropped in a later release, the schema key won't need to change but the detector id and grammar keyword will — the current asymmetry makes that migration more confusing, not less.

Easiest fix: rename detector id, schema key, and config property to cynefin-beta to match the keyword. (If the intent was specifically to avoid renaming the config block when going GA, please add a short comment to that effect on the schema entry so the inconsistency is discoverable.)

💡 [suggestion] Transition control-point coordinate math is fiddly

In cynefinRenderer.ts (transitions section), x1/y1/x2/y2 and mx/my are computed in padded SVG coords, then cpx/cpy subtract padding to land in root-local coords to match the M/Q path which uses unpadded fromLayout.cx,cy. It works, but a future reader has to hold two coordinate spaces in their head. Computing everything in root-local (drop the + padding on x1…y2, drop the - padding on cpx/cpy) would be algebraically equivalent and easier to follow.

💡 [suggestion] Overflow badge only for the confusion ellipse

MAX_CONFUSION_ITEMS = 3 caps confusion with a +N more badge, but the four quadrant domains can visually overflow their boxes with a long list. Not a blocker for v1 — the wavy boundaries are forgiving — but worth either applying the same pattern or documenting the expectation that quadrant item counts should be kept small.

💡 [suggestion] PR description test-plan checkboxes are stale

The PR body lists Cypress e2e and Cynefin unit/integration tests as unchecked ("happy to add if requested"), but cypress/integration/rendering/cynefin.spec.js, cynefin.spec.ts, and cynefin.integration.spec.ts are all present. A quick edit of the description will avoid a reviewer chasing those down.

Really excited about this one — let's get it across the finish line. 🙌

ragelink and others added 2 commits April 17, 2026 10:03
- Honor `useMaxWidth` config in renderer (match radar reference pattern)
- Rename config/detector/schema key to `cynefin-beta` to match keyword
  and align with the `wardley-beta` convention
- Simplify transition control-point math into a single coordinate space
- Document the expectation that quadrant item counts stay small
@ragelink
Copy link
Copy Markdown
Contributor Author

Thanks so much for the thorough pass, @knsv — really appreciate the care on this one. Pushed the fixes in dfa88d76; quick map of where each item landed:

🟡 useMaxWidth now honored

packages/mermaid/src/diagrams/cynefin/cynefinRenderer.ts#L101

configureSvgSize(svg, totalHeight, totalWidth, config.useMaxWidth ?? true);

Matches the radar pattern exactly.

🟡 Renamed to cynefin-beta to match the keyword

Applied the full rename as suggested — keyword, detector id, schema key, and config property all line up now:

  • Detector id — cynefinDetector.ts#L7: const id = 'cynefin-beta';
  • Schema key — config.schema.yaml#L338: cynefin-beta:
  • Config reads — cynefinDb.ts#L73-L74: DEFAULT_CONFIG['cynefin-beta'] / commonGetConfig()['cynefin-beta']
  • Also swept: config.type.ts, defaultConfig.ts, .build/jsonSchema.ts, the Cypress spec ({ 'cynefin-beta': {...} }), and the multi-diagram-id-uniqueness map.

Note: the theme-variable block stays as themeVariables.cynefin — that mirrors wardley's split (config key wardley-beta, theme var wardley) so a future GA rename doesn't churn user theme overrides. Happy to switch that too if you'd prefer.

💡 Transition control-point math simplified

cynefinRenderer.ts transitions section — everything now computed in root-local coordinates; the + padding / - padding round-trip is gone. Reads straight through without the coordinate-space juggling.

💡 Overflow expectation documented

Added a note under Items in src/docs/syntax/cynefin.md calling out the confusion cap + suggesting small per-quadrant item counts. Left the quadrants themselves uncapped in v1 to keep behavior predictable — happy to add a +N more badge there in a follow-up if it comes up.

💡 PR description refreshed

Test plan now reflects the existing Cypress spec (cypress/integration/rendering/cynefin.spec.js) and the unit + integration suites (cynefin.spec.ts, cynefin.integration.spec.ts) — sorry for the stale checkboxes.

Also verified locally: 36 cynefin tests + 31 uniqueness tests + 238 parser tests all pass, tsc --noEmit clean, docs regenerated. Thanks again — this was a genuinely helpful review. 🙌

@ragelink ragelink requested a review from knsv-bot April 17, 2026 16:36
@ashishjain0512
Copy link
Copy Markdown
Collaborator

Hey @ragelink

Thanks for keeping up with this one.
I reviewed and approved the Argos check; it's green now.

I see some unit test checks on the CI are failing. Can you check?

ragelink and others added 5 commits April 27, 2026 09:55
- Move cypress/integration/rendering/cynefin.spec.js into a cynefin/
  subfolder so e2e-diagram-scope.spec.ts (every diagram folder must
  have a matching spec subfolder) passes.
- Update packages/examples/src/examples/cynefin.ts id from 'cynefin' to
  'cynefin-beta' to match the registered detector id, satisfying
  example.spec.ts (every registered diagram must have an example).
Aligns Cynefin with the radar diagram convention so that the diagram's
internal identity matches the rest of the codebase. Previously cynefin
diverged: the registered detector id and config key were 'cynefin-beta',
which forced bracket-access (DEFAULT_CONFIG['cynefin-beta']) — the only
such case in defaultConfig.ts. Radar by contrast uses id 'radar' / config
key 'radar' with the '-beta' marker living only in the syntax keyword.

Changes:
- Detector id: 'cynefin-beta' -> 'cynefin'
- Config schema key (cynefin-beta -> cynefin) in config.schema.yaml,
  defaultConfig.ts, .build/jsonSchema.ts, and the regenerated
  config.type.ts
- Example id back to 'cynefin' (matches the registered diagram id)
- Test/spec config-object keys updated (multi-diagram uniqueness spec,
  cypress cynefin spec)
- Docs source updates for the config-key references; generated docs
  regenerated via pnpm --filter mermaid docs:build

Unchanged: the syntax keyword 'cynefin-beta' remains the trigger token
in the Langium grammar, parser tokenBuilder, detector regex, and all
diagram code examples — exactly mirroring radar-beta.
@ragelink
Copy link
Copy Markdown
Contributor Author

Hey @ashishjain0512 — thanks for the nudge! Pushed two commits to fix the failing unit checks:

  • 100d8ced9 addresses the two failures directly:

    • scripts/e2e-diagram-scope.spec.ts was failing because the new "every diagram folder needs a matching spec subfolder" check (added in feat(ci): diagram-scoped e2e test selection #7619) expected cypress/integration/rendering/cynefin/. Moved cynefin.spec.js into that subfolder.
    • packages/examples/src/example.spec.ts was failing because the example's id didn't match the registered diagram id.
  • 0323b9052 is a small follow-up cleanup. While fixing the example id mismatch I noticed Cynefin had diverged from the radar convention — the registered detector id and config key were cynefin-beta (forcing bracket-access in defaultConfig.ts, the only such case). Aligned with the radar pattern: the registered id and config key are now plain cynefin, while the syntax keyword cynefin-beta (Langium grammar, parser tokens, code examples) is unchanged. So users still write cynefin-beta to declare a diagram, and now configure it under config.cynefin — matching how radar-beta / config.radar works.

Full vitest suite passes locally (4,131 / 4,131). Let me know if anything else needs tweaking.

ragelink and others added 2 commits April 27, 2026 20:04
Moving cynefin.spec.js into cypress/integration/rendering/cynefin/
broke the relative import for ../../helpers/util — needs an extra
level (../../../helpers/util) to match the radar and wardley specs.
@knsv
Copy link
Copy Markdown
Collaborator

knsv commented Apr 29, 2026

Alright @ragelink! Thanks for the contribution and stamina. I think is ready now!

@ragelink
Copy link
Copy Markdown
Contributor Author

ragelink commented May 5, 2026

Alright @ragelink! Thanks for the contribution and stamina. I think is ready now!

\o/ thank you so much for your help @knsv !

@ragelink
Copy link
Copy Markdown
Contributor Author

ragelink commented May 5, 2026

Hello @knsv sorry to bug, one small follow-up as I'm a bit unfamiliar with the process, what happens next? does this go into a queue for merging? is there any additional work needed on my end?

Thanks!

Copy link
Copy Markdown
Collaborator

@knsv-bot knsv-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[sisyphus-bot]

Hey @ragelink — final pass to formally close this out. No new findings; the prior rounds covered everything substantive, and nothing has shifted under the Cynefin code since @knsv approved on April 29 (only the merges from develop and a couple of CI-scoping fix-ups).

Worth restating why this lands well, because four review rounds in it's easy to lose sight of the win:

  • 🎉 Genuinely novel — first text-based DSL for Cynefin anywhere.
  • 🎉 Clean architecture: Langium grammar with a closed DOMAIN_NAME enum, deterministic seeded PRNG behind the wavy boundaries in their own module, and full theme integration across all five themes.
  • 🎉 Solid test coverage end-to-end — DB unit tests, parser integration tests, boundary determinism, multi-diagram ID uniqueness, and Cypress visual cases including the cliff and confusion overlay.
  • 🎉 The persistence across multiple review rounds — including chasing the Argos and CI fix-ups at the end — is exactly the kind of follow-through that makes new diagram types ship. Genuinely appreciated.

To answer your "what happens next" question: nothing further needed from you. The PR is approved and a maintainer will merge it when the timing fits — likely bundled with the next mermaid minor bump given this is a feat: change. You can ignore the queue from here; if develop shifts under you and a conflict shows up, someone will ping you. Otherwise sit back and watch it land.

Thanks again for the stamina on this one. 🎉

@knsv knsv added this pull request to the merge queue May 6, 2026
Merged via the queue into mermaid-js:develop with commit bcb2bb3 May 6, 2026
24 checks passed
@mermaid-bot
Copy link
Copy Markdown

mermaid-bot Bot commented May 6, 2026

@ragelink, Thank you for the contribution!
You are now eligible for a year of Premium account on MermaidChart.
Sign up with your GitHub account to activate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Type: Enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add Cynefin framework diagram type

4 participants