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>
6.9 KiB
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.
DiagramRendererprotocol:can_render(diagram_type: str) -> bool,render(source: str, diagram_type: str, output_path: Path) -> RendererResultRendererResult:success: bool,output_path: Path | None,warning: WarningRecord | Nonedetect_renderers() -> dict[str, DiagramRenderer]— probe PATH formmdc,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: checksshutil.which("mmdc")MermaidRenderer.render(source, "mermaid", output_path):- Write source to a temp
.mmdfile - 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"))
- Write source to a temp
- 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
mmdctopyproject.tomloptional extras:diagram-mermaid - Integration test (skipped if
mmdcnot 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: checksshutil.which("dot")GraphvizRenderer.render(source, "graphviz", output_path):- Write source to a temp
.dotfile - Run
dot -Tpng <input> -o <output>.png - On success / failure: same pattern as MermaidRenderer
- Write source to a temp
- Alt-text marker:
[graphviz-source]<source>for round-trip - Add
graphvizto optional extras:diagram-graphviz - Integration test (skipped if
dotnot 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: checksshutil.which("plantuml")PlantUMLRenderer.render(source, "plantuml", output_path):- Write source to a temp
.pumlfile - Run
plantuml -tpng <input>(output written adjacent to input by default) - Move/rename output PNG to
output_path - On success / failure: same pattern
- Write source to a temp
- Alt-text marker:
[plantuml-source]<source> - Add
plantumlto optional extras:diagram-plantuml - Integration test (skipped if
plantumlnot 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.mdwith 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
differreports zero broken diagrams when renderer was available
- Each test is
- 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 T02–T04 (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 T02–T04 (needs the renderers to test the rendered path)
- Use
pytest.mark.skipifto 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:
- Every task block has
status: done - Workplan frontmatter
status: done - All existing tests pass unchanged (source-only fallback unbroken)
- On a system with
mmdc:pytest tests/regression/test_level3_rendered_diagrams.pypasses ruff checkandmypyclean- Optional extras
diagram-mermaid,diagram-graphviz,diagram-plantumldocumented inpyproject.toml