Files
marki-docx/workplans/MRKD-WP-0005-diagram-renderer-integration.md
Bernd Worsch 039420caee chore: add workplans WP-0004, WP-0005, WP-0006
WP-0004: Stable Documentation Corpus & Architecture Records
WP-0005: Diagram Renderer Integration
WP-0006: Packaging & Distribution

State-hub workstreams and tasks created; local_path registration deferred
pending path mismatch fix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 12:55:34 +00:00

6.9 KiB
Raw Blame History

id, type, domain, repo, status, state_hub_workstream_id, created, updated
id type domain repo status state_hub_workstream_id created updated
MRKD-WP-0005 workplan markitect marki-docx active 2ef47f11-d828-436d-8955-c58e13c50752 2026-03-16 2026-03-16

MRKD-WP-0005 — Diagram Renderer Integration

Complete the deferred rendering path for FR-533/534. Currently diagrams.py operates in source-only mode: diagram fenced blocks are preserved as source through the round-trip but are never rendered to images. This workstream adds actual rendering support for Mermaid, Graphviz, and PlantUML when the corresponding CLI tools are available, while preserving the graceful source-only fallback when they are not.

Scope: FR-533 (auto-diagram support), FR-534 (diagram intent preservation), FR-538 (processor-dependency disclosure) Out of scope: new diagram syntaxes beyond mermaid/graphviz/plantuml Depends on: MRKD-WP-0003 (diagrams.py source-only foundation) — complete


T01 — Renderer abstraction layer and detection

id: MRKD-WP-0005-T01
status: todo
priority: high
state_hub_task_id: c4911ecc-1e3c-4d22-a6fb-92d1ed319274

Introduce a RendererBackend abstraction in diagrams.py so that each diagram type can be rendered by a pluggable backend. The builder calls the abstraction; concrete backends handle tool detection and subprocess invocation.

  • DiagramRenderer protocol: can_render(diagram_type: str) -> bool, render(source: str, diagram_type: str, output_path: Path) -> RendererResult
  • RendererResult: success: bool, output_path: Path | None, warning: WarningRecord | None
  • detect_renderers() -> dict[str, DiagramRenderer] — probe PATH for mmdc, dot, plantuml; return only those found
  • Builder updated to call detect_renderers() at build time; if a renderer is found for the diagram type → render to PNG and embed; if not → source-only fallback + WarningRecord(reason="renderer-unavailable", construct=diagram_type) (FR-538)
  • Unit tests: test_renderer_detection — mock PATH; test_fallback_when_no_renderer

Deliverable: pytest tests/test_level3_diagrams.py still passes; renderer abstraction in place and tested.


T02 — Mermaid CLI (mmdc) integration

id: MRKD-WP-0005-T02
status: todo
priority: high
state_hub_task_id: 87caa295-f466-4e2e-ba06-4b1a801ca976

Implement the MermaidRenderer backend that shells out to mmdc (Mermaid CLI).

  • MermaidRenderer.can_render("mermaid") -> bool: checks shutil.which("mmdc")
  • MermaidRenderer.render(source, "mermaid", output_path):
    • Write source to a temp .mmd file
    • Run mmdc -i <input> -o <output>.png
    • On success: return RendererResult(success=True, output_path=...)
    • On failure: return RendererResult(success=False, warning=WarningRecord(reason="render-failed"))
  • Builder: PNG embedded into DOCX as image; alt-text carries [mermaid-source]<source> marker for round-trip (FR-534)
  • Importer: existing alt-text marker detection already handles this — verify round-trip works
  • Add mmdc to pyproject.toml optional extras: diagram-mermaid
  • Integration test (skipped if mmdc not found): test_mermaid_render_roundtrip

Deliverable: When mmdc is on PATH, mermaid diagrams render to PNG and embed in DOCX; round-trip restores source. When absent, source-only fallback with warning.


T03 — Graphviz (dot) integration

id: MRKD-WP-0005-T03
status: todo
priority: medium
state_hub_task_id: 8ceb771d-0b16-452d-b1cc-c5c2c40fe723

Implement the GraphvizRenderer backend that shells out to dot.

  • GraphvizRenderer.can_render("graphviz") -> bool: checks shutil.which("dot")
  • GraphvizRenderer.render(source, "graphviz", output_path):
    • Write source to a temp .dot file
    • Run dot -Tpng <input> -o <output>.png
    • On success / failure: same pattern as MermaidRenderer
  • Alt-text marker: [graphviz-source]<source> for round-trip
  • Add graphviz to optional extras: diagram-graphviz
  • Integration test (skipped if dot not found): test_graphviz_render_roundtrip

Deliverable: When dot is on PATH, graphviz diagrams render and embed; otherwise source-only fallback.


T04 — PlantUML integration

id: MRKD-WP-0005-T04
status: todo
priority: medium
state_hub_task_id: ab0da6e4-a0f2-4a57-baac-5727b741c74f

Implement the PlantUMLRenderer backend that shells out to plantuml.

  • PlantUMLRenderer.can_render("plantuml") -> bool: checks shutil.which("plantuml")
  • PlantUMLRenderer.render(source, "plantuml", output_path):
    • Write source to a temp .puml file
    • Run plantuml -tpng <input> (output written adjacent to input by default)
    • Move/rename output PNG to output_path
    • On success / failure: same pattern
  • Alt-text marker: [plantuml-source]<source>
  • Add plantuml to optional extras: diagram-plantuml
  • Integration test (skipped if plantuml not found): test_plantuml_render_roundtrip

Deliverable: When plantuml is on PATH, PlantUML diagrams render and embed.


T05 — Rendered diagram round-trip integration tests

id: MRKD-WP-0005-T05
status: todo
priority: medium
state_hub_task_id: 65b67ed9-5862-4322-acfb-5d39dab7e8d5

Extend the regression corpus and test harness to cover the rendered-diagram path end-to-end, in addition to the existing source-only tests.

  • Add tests/regression/level3/rendered_diagrams_document.md with mermaid, graphviz, and plantuml blocks
  • tests/regression/test_level3_rendered_diagrams.py:
    • Each test is pytest.mark.skipif(shutil.which("mmdc") is None, ...)
    • Full round-trip: build → import → compare; assert diagrams preserved
    • Assert differ reports zero broken diagrams when renderer was available
  • Verify existing test_level3_diagrams.py (source-only) still passes regardless of renderer availability — the fallback path must remain stable

Deliverable: Rendered-diagram regression tests pass on systems with renderers installed; source-only tests pass on all systems.


How to Work

  • T01 must be complete before T02T04 (abstraction must exist before concrete backends)
  • T02, T03, T04 are independent of each other — can be worked in any order or in parallel
  • T05 depends on T02T04 (needs the renderers to test the rendered path)
  • Use pytest.mark.skipif to gate renderer-dependent tests — never fail on missing tools

Updating Task Status

status: todo        →  status: in_progress   (when you start it)
status: in_progress →  status: done          (when verified complete)

When every task is done, set the frontmatter status: done.

Success Criteria

Before marking the workplan done:

  1. Every task block has status: done
  2. Workplan frontmatter status: done
  3. All existing tests pass unchanged (source-only fallback unbroken)
  4. On a system with mmdc: pytest tests/regression/test_level3_rendered_diagrams.py passes
  5. ruff check and mypy clean
  6. Optional extras diagram-mermaid, diagram-graphviz, diagram-plantuml documented in pyproject.toml