Orchestrata Ultimate › Plans › diagram-to-code-parity
Diagram-to-Code Parity Report
Source: plans/diagram-to-code-parity.md at 8a2cb42ad · last changed 2026-07-27 · first committed 2026-07-13 · 160 lines.
Prose pending.
Plan text
Diagram-to-Code Parity Report
Context
orchestrata_tools.diagram.diagram_to_code.DiagramToCode (src/orchestrata_tools/diagram/diagram_to_code.py) was the original Mermaid classDiagram → Python skeleton generator. A newer generator, gen-skeleton, has been built inside scripts/serialize_codebase_ast.py (lines ~3000–5300 and CLI setup at ~9429–9460) as the "build-factory linchpin" for contract-driven, @traces'd skeletons. This report compares the two feature-by-feature, notes what is still unique to each, lists the tests that would migrate if DiagramToCode were retired, and gives a recommendation.
No source files are changed by this report.
1. Summary of both tools
DiagramToCode (src/orchestrata_tools/diagram/diagram_to_code.py)
A general-purpose reverse parser. It takes a Mermaid classDiagram, builds a list of ParsedClass objects (ParsedClass dataclass at diagram_to_code.py:28), and can emit either a single Python module or a per-namespace/per-class file tree. It is the backend used by the round-trip verifier and the spec-compliance auditor (generate_comprehensive_audit.py).
Key entry points:
parse(diagram)—diagram_to_code.py:167generate_code(parsed, …, per_module=False, include_imports=True)—diagram_to_code.py:406write_modules(parsed, output_dir)—diagram_to_code.py:677
gen-skeleton (scripts/serialize_codebase_ast.py)
A contract-first generator tuned for the orchestrata-ultimate build factory. It reads analyst-authored Mermaid contracts (e.g. plans/contracts/SPEC-072.mmd) and emits typed Python skeletons with @traces decorators, # IMPLEMENT: leaf markers, a companion trace-map JSON, and built-in failure-detection gates.
Key entry points:
generate_skeleton(diagram_text)—scripts/serialize_codebase_ast.py:4649generate_skeleton_modules(diagram_text)—scripts/serialize_codebase_ast.py:4693- CLI
gen-skeleton/skeleton-diff—scripts/serialize_codebase_ast.py:9429andscripts/serialize_codebase_ast.py:10187
2. Feature parity table
| Feature | gen-skeleton (scripts/serialize_codebase_ast.py) |
DiagramToCode (src/orchestrata_tools/diagram/diagram_to_code.py) |
Notes |
|---|---|---|---|
Parse classDiagram blocks |
_parse_skeleton_diagram :3376 |
parse :167 |
Both preserve declaration order. |
Parse namespace … { … } blocks |
_SKEL_NAMESPACE_OPEN_RE :3174, namespace stored on _SkelClass :3121 |
parse namespace branch :183–187, ParsedClass.namespace :43 |
Both group output by namespace. |
Class header stereotypes (class X <<stereo>> {) |
_SKEL_CLASS_OPEN_RE :3132, _SkelClass.stereotype :3114 |
parse class match :188–194, ParsedClass.stereotypes :33 |
DiagramToCode supports multiple comma-separated stereotypes; gen-skeleton uses the first one as the emitter key. |
In-body stereotype/decorator lines (<<abstract>>) |
Parsed as the class stereotype if none on header :3434–3437 | _parse_class_member decorator branch :223–225, ParsedClass.decorators :34 |
Gen-skeleton merges body <<…>> into the class stereotype; DiagramToCode keeps them as separate decorators. |
| Parse fields with type/default | _SkelField :3067, _parse_skeleton_field_line :3305 |
ParsedClass.variables :35, _parse_class_member var branch :280–296 |
Both handle name: type = default. |
| Parse methods with params/return/async | _SkelMethod :3085, _parse_skeleton_method_line :3284 |
FunctionInfo via _parse_class_member method branch :228–277 |
Both handle async, bracket decorators, defaults, return types. |
Bracket decorators ({classmethod}, {staticmethod}, {property}, {abstractmethod}) |
_skeleton_method_decorator_lines :3759 |
_parse_class_member :244–276 and _generate_method :593–623 |
Gen-skeleton emits real decorators and resolves @property/@abstractmethod order; DiagramToCode stores flags in fi._extra. |
Mermaid tilde generics (List~str~) |
_convert_skeleton_tildes :3137 |
_mermaid_type_to_python :94–108 |
Gen-skeleton handles nested tildes deterministically; DiagramToCode uses an alternating [/] walk that can mis-pair nested spans. |
| Relationship: inheritance `A < | -- B` | Parsed but not used (gen-skeleton reads `.. | >` only) |
| Relationship: realization `A .. | > B` | _SKEL_REALIZATION_RE :3181, A.bases.append(B) :3418–3421 |
_parse_relationship implementation :370–373, B.implements.append(A) :392–393 |
| Relationship: composition/aggregation/dependency/association/link | Not parsed | _parse_relationship :367–402 tracks all five; composition/aggregation/dependency become docstring markers :559–570 |
DiagramToCode round-trip tests exercise all seven arrows (tests/test_diagram_to_code_roundtrip.py). |
| Per-module / namespace output | generate_skeleton_modules :4693 writes one .py per namespace |
generate_code(..., per_module=True) :406–417 and write_modules :677 |
DiagramToCode can also split per class and emit __init__.py files; gen-skeleton emits one file per namespace. |
| Cross-module imports | Local types resolved against the full class table (_SkelEmitContext.classes :3609) |
_extract_type_references :143–160, _generate_file_code :625–657 generates sibling imports |
Gen-skeleton never fabricates an import path; DiagramToCode auto-generates from <ns>.<file> import <Name>. |
__init__.py generation |
Not part of gen-skeleton (separate gen-facade subcommand exists at :9468) |
_generate_init_code :659–675, write_modules :677–735 |
DiagramToCode writes package __init__.py with __all__. |
| Enum emission | _EnumEmitter :4165 → StrEnum |
_generate_class enum branch :573–576 → Enum |
Gen-skeleton lower-cases values unless an explicit = value is given; DiagramToCode always emits Name = "Name". |
| Dataclass emission | _DataclassEmitter :4101 → @dataclass(slots=True) |
Detected via dataclass stereotype/decorator :464–465, @dataclass emitted :534–537 |
Gen-skeleton converts mutable defaults to field(default_factory=…); DiagramToCode emits them raw. |
Pydantic BaseModel emission |
Not supported | _generate_imports :466–467, _generate_class :545–548 |
No <<pydantic>> emitter in gen-skeleton. |
Abstract base class emission (ABC) |
Not supported as a class-level stereotype ({abstractmethod} bracket only) |
_generate_imports :468–469, _generate_class :550–553 |
DiagramToCode can emit class X(ABC):; gen-skeleton emits ABC only via individual @abstractmethod decorators. |
| Protocol emission | _ProtocolEmitter :4052 → typing.Protocol + @runtime_checkable |
Detected via implements :470–471 |
Both emit class X(Protocol):. |
<<Tool>> stereotype / command boilerplate |
_ToolEmitter :4327, full execute wrapper with ToolResult, tracer span, try/except :3901–3983 |
Not supported | Gen-skeleton's signature feature. |
| Constructor DI generation | _emit_composed_init_lines :4185 |
Not supported | Gen-skeleton wires private fields to self._x and public fields to self.x; handles _tracer default. |
| Accessor/factory/leaf patternRole dispatch | _skeleton_method_role :3728, _emit_accessor_method_lines :3837, _emit_leaf_method_lines :3792 |
Not supported | Gen-skeleton generates return self._field for accessors and marked # IMPLEMENT: stubs for leaves. |
| Self-returning factory heuristic | _skeleton_is_self_returning_factory_name :3350 |
Not supported | Bare create/default/from_* returning the class type become @classmethod in gen-skeleton. |
| Base read-only property collision handling | _introspect_base_readonly_property :3659, _skeleton_field_is_readonly_property :3687 |
Not supported | Gen-skeleton introspects real bases (e.g. BaseTool.metadata) to avoid AttributeError. |
@traces emission |
_traces_call :3708, class/method pragma parsing :3175–3176 |
Not supported | Gen-skeleton's core requirement-traceability feature. |
| Trace-map JSON | _build_skeleton_trace_map :4453 |
Not supported | Maps REQ-* → {file, class, method}. |
Leaf-map JSON + # IMPLEMENT: markers |
_build_skeleton_leafmap :4495, _emit_leaf_method_lines :3826–3833 |
Not supported | Used by skeleton-diff Gate 3. |
| Failure-detection gates | Gate 0 gate0_construction_smoke :4890, Gate 2 gate2_leaf_fraction_table :4964, Gate 3 skeleton_diff :5157, self-verify _gen_skeleton_self_verify_traces :5027 |
Not supported | Gen-skeleton runs gates automatically in the CLI (run_gen_skeleton_gates :5069). |
%% extend <path> merge mode |
_SKEL_EXTEND_RE :3178, _SkelClass.mode :3125 |
Not supported | Allows a contract to declare that a class extends an existing implementation. |
%% REUSE … cross-package import resolution |
_parse_skeleton_reuse_imports :3539, _build_skeleton_known_types :3573 |
Not supported | Gen-skeleton resolves declared external types to real imports; unresolved types are flagged, never guessed. |
PEP 695 type parameters (class X~T~) |
_skel_generic_suffix :3589, _SkelClass.type_params :3124 |
Not supported | Gen-skeleton emits class X[T]:. |
| Partial success / no-stereotype fallback | _select_skeleton_emitter :4445, warning/fallback at :4555–4587 |
All-or-nothing for a given input | Gen-skeleton skips one bad stereotype and falls back a bare class to <<class>>; DiagramToCode raises if it cannot handle a decorator in write_modules. |
include_imports=False toggle |
Not available | generate_code(..., include_imports=False) :406, :481 |
DiagramToCode can emit code without imports. |
import asyncio for async methods |
Not emitted | _generate_imports :473–474 |
DiagramToCode adds import asyncio when any method is async. |
3. Features still ONLY in DiagramToCode
These capabilities have no equivalent in gen-skeleton today:
- Pydantic
BaseModelemission (diagram_to_code.py:345–353,:545–548). A<<pydantic>>stereotype or decorator producesfrom pydantic import BaseModelandclass X(BaseModel):. - Abstract base class (
ABC) emission (diagram_to_code.py:355–357,:550–553). A class-level<<abstract>>stereotype/decorator producesfrom abc import ABC, abstractmethodandclass X(ABC):. - Relationship docstrings (
diagram_to_code.py:559–570). Composition, aggregation, and dependency arrows are rendered into the class docstring asComposes: …,Aggregates: …,Depends on: …. - Full relationship tracking (
diagram_to_code.py:367–402). All seven Mermaid arrows (inheritance, realization, composition, aggregation, dependency, association, link) are parsed and stored; the round-trip test suite (tests/test_diagram_to_code_roundtrip.py) depends on this. - Per-class file output and
__init__.pygeneration (diagram_to_code.py:625–735).write_modulessplits enums intotypes.py, non-enums intosnake_case.py, and writes package__init__.pyfiles with__all__. - Auto-generated cross-module imports (
diagram_to_code.py:143–160,:625–657). Type references to sibling modules are turned into realfrom <pkg>.<module> import <Name>lines. include_imports=Falseoption (diagram_to_code.py:406,:481). Useful for embedding generated code into a larger file that already has imports.import asynciogeneration (diagram_to_code.py:473–474). Any async method causes animport asyncioline.- Return-type arrow-prefix stripping (
diagram_to_code.py:239–242). Handles Mermaid like+run() ->int. - Parameter kind metadata (
positional/varargs/kwargs) (diagram_to_code.py:348–355).DiagramToCodeexplicitly classifies*args/**kwargs.
4. Features only in gen-skeleton
These capabilities are unique to the build-factory generator:
@tracesdecorator emission (scripts/serialize_codebase_ast.py:3708,:4052,:4101, etc.) driven by%% traces spec=… story=… reqs=…pragmas (:3175–3176).- Method-level trace overrides (
scripts/serialize_codebase_ast.py:3176,:3328–3332). - Trace-map JSON (
scripts/serialize_codebase_ast.py:4453). - Leaf-map JSON and
# IMPLEMENT:stubs (scripts/serialize_codebase_ast.py:4495,:3826–3833). - Failure-detection gates:
- Gate 0 construction smoke (
:4890), - Gate 2 leaf-fraction table (
:4964), - Gate 3
skeleton-diff(:5157), - check-traces self-verify (
:5027).
- Gate 0 construction smoke (
<<Tool>>stereotype with full command boilerplate (scripts/serialize_codebase_ast.py:4327,:3901–3983) —executegets arg validation, tracer span, try/except,ToolResultwrapping, and delegation to a matching leaf.- Constructor DI synthesis (
scripts/serialize_codebase_ast.py:4185) with auto_tracerinjection for Tools (:4344). - patternRole dispatch (
scripts/serialize_codebase_ast.py:3728) —command,accessor,factory,leaf. <<class>>plain composed service emitter (scripts/serialize_codebase_ast.py:4386).- Self-returning factory heuristic (
scripts/serialize_codebase_ast.py:3350) — barecreate/default/from_*returning the class type become@classmethod. - Base read-only property introspection (
scripts/serialize_codebase_ast.py:3659,:3687) to avoid collisions with real base descriptors. %% REUSE …import resolution (scripts/serialize_codebase_ast.py:3539,:3573) plus honest "unresolved type" notes.%% extend <path>merge mode (scripts/serialize_codebase_ast.py:3178,:3125).- PEP 695 type parameters (
scripts/serialize_codebase_ast.py:3589,:3124). - Multi-module namespace routing to real files (
scripts/serialize_codebase_ast.py:4693, CLI handler:10195–10246). - Partial success / no-stereotype fallback (
scripts/serialize_codebase_ast.py:4555–4587). - Nested-tilde generic conversion (
scripts/serialize_codebase_ast.py:3137).
5. Tests that would migrate if DiagramToCode were retired
The existing test files that directly exercise DiagramToCode are:
tests/test_orchestrata_tools_diagram_to_code.pytests/test_diagram_to_code_roundtrip.py
If DiagramToCode were retired, the tests would split as follows:
| Current test | What it covers | Would migrate to / become |
|---|---|---|
test_orchestrata_tools_diagram_to_code.py — parser tests for stereotypes, fields, methods, namespaces, decorators, params, return types |
Shared Mermaid parsing behaviour | tests/scripts/test_ast_gen_skeleton.py (or a new test_ast_gen_skeleton_parsing.py) |
test_orchestrata_tools_diagram_to_code.py — relationship parsing tests |
The seven Mermaid arrows | A new gen-skeleton relationship suite, but only if gen-skeleton learns to track composition/aggregation/dependency/association/link |
test_orchestrata_tools_diagram_to_code.py — generate_code() output tests (enum, dataclass, pydantic, abstract, Protocol, typing imports) |
Code emission for stereotypes | tests/scripts/test_ast_gen_skeleton.py for enum/dataclass/Protocol; pydantic/ABC tests would need new gen-skeleton emitters or be deleted |
test_orchestrata_tools_diagram_to_code.py — per_module=True and write_modules tests |
Namespace/multi-file output | Extend tests/scripts/test_ast_gen_skeleton.py namespace tests and/or add gen-facade integration tests |
test_diagram_to_code_roundtrip.py |
Forward generator round-trip for inheritance only; model tracking for all seven arrows | Retire the round-trip assertions that have no gen-skeleton equivalent, or keep DiagramToCode as the relationship parser |
tests/scripts/test_ast_gen_skeleton.py and tests/scripts/test_ast_skeleton_gates.py already cover the gen-skeleton side and would not need to migrate.
6. Recommendation
Do not retire or deprecate DiagramToCode. The two tools serve different purposes and each has capabilities the other lacks:
gen-skeletonis the build-factory contract generator: it is the right tool for turning analyst-authoredplans/contracts/*.mmdfiles into@traces'd, gate-verified Python skeletons.DiagramToCoderemains the general-purpose diagram-to-code utility: it supports pydantic/ABC stereotypes, full relationship tracking, per-class file layout with__init__.py, and is wired into the round-trip verifier and the comprehensive audit.
Recommended actions:
- Keep both tools. Treat
gen-skeletonas the preferred generator for new build-factory contracts, andDiagramToCodeas the supported general-purpose parser/generator. - Do not delete any tests. The
DiagramToCodetest files cover behaviour (especially relationships and pydantic/ABC emission) that gen-skeleton does not yet implement. - If future unification is desired, port the truly unique
DiagramToCodefeatures into gen-skeleton as new emitters/options rather than removing them:- Add
<<pydantic>>and<<abstract>>class-level emitters. - Add relationship tracking for composition/aggregation/dependency/association/link.
- Add an optional per-class file writer with
__init__.pygeneration. - Reconcile the realization-arrow direction convention (
A ..|> B) so both tools can agree on a single interpretation.
- Add
- Add cross-references in docstrings so future maintainers know which generator to use for which workflow.
Until the unique DiagramToCode features are duplicated in gen-skeleton, retiring it would break the round-trip tests, the audit pipeline, and any workflow that relies on pydantic/ABC classes or per-class file output.