Files
markitect-main/markitect/prompts/visualization/graph.py
tegwick 7b4bd461c9 feat(prompts): implement Phase 8 - Observability & Traceability (FR-11)
Complete implementation of Phase 8, the final phase of prompt dependency
resolution infrastructure, adding full observability and traceability.

## Features (FR-11)

### FR-11.1: Complete Artifact Provenance Tracing
- TraceabilityService: composition layer for full artifact lineage
- Trace any artifact to producing PromptTemplate, input artifacts,
  generator runs, and quality validation results
- ProvenanceTrace model with complete dependency chain reconstruction
- RunSummary and ArtifactLineage models for structured trace output

### FR-11.2: Recomputation Query Infrastructure
- PromptQueryService: cross-service complex queries
- Run history queries with template and status filters
- Stale artifact detection via impact debt analysis
- Dependency graph statistics (nodes, edges, cycles, roots, leaves)
- Content-based artifact lookups by digest

### Visualization Support
- GraphExporter: DOT (Graphviz) and Mermaid format export
- Supports all edge types (requires, generates, includes)
- Handles isolated nodes, linear chains, diamonds, and complex graphs

### CLI Commands (prompt group)
- `prompt trace <artifact_id>` - Full provenance trace as JSON
- `prompt graph <artifact_id>` - Dependency graph (DOT/Mermaid)
- `prompt runs` - List execution runs with filters
- `prompt debt` - Show impact debt and stale artifacts
- `prompt stats` - Dependency graph statistics

## Implementation

Source files (8):
- markitect/prompts/traceability/models.py - Trace data models
- markitect/prompts/traceability/service.py - TraceabilityService
- markitect/prompts/visualization/graph.py - Graph export
- markitect/prompts/queries/operations.py - PromptQueryService
- markitect/prompts/cli.py - Click CLI commands
- Package __init__.py files (3)

Tests (64 total, all passing):
- tests/unit/prompts/test_traceability_service.py (21 tests)
- tests/unit/prompts/test_visualization.py (14 tests)
- tests/unit/prompts/test_query_operations.py (12 tests)
- tests/integration/prompts/test_traceability_workflow.py (7 tests)
- tests/integration/prompts/test_prompt_cli.py (10 tests)

## Architecture

TraceabilityService is a composition layer that delegates to:
- DependencyQueryService (transitive dependency lookups)
- QualityValidator (validation history)
- IncrementalExecutionEngine (impact debt queries)
- Direct repository access (artifacts, edges)

No duplicate data storage - all data comes from existing Phase 1-7
infrastructure (artifact repo, dependency repo, validation DB, debt DB).

## Verification

All 2250 tests pass with 0 regressions.
Phase 8 completes the full 8-phase implementation roadmap.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-09 20:32:18 +01:00

107 lines
3.3 KiB
Python

"""
Graph visualization export for dependency graphs.
Exports DependencyGraph to DOT (Graphviz) and Mermaid diagram formats.
"""
from markitect.prompts.dependencies.models import DependencyGraph, EdgeType
# Edge type to style mappings
_DOT_EDGE_STYLES = {
EdgeType.REQUIRES: 'style="solid"',
EdgeType.GENERATES: 'style="dashed"',
EdgeType.INCLUDES: 'style="dotted"',
}
_MERMAID_EDGE_STYLES = {
EdgeType.REQUIRES: "-->",
EdgeType.GENERATES: "-.->",
EdgeType.INCLUDES: "==>",
}
class GraphExporter:
"""Export DependencyGraph to DOT and Mermaid formats."""
@staticmethod
def to_dot(graph: DependencyGraph, title: str = "Dependencies") -> str:
"""
Export dependency graph to Graphviz DOT format.
Args:
graph: DependencyGraph to export
title: Graph title
Returns:
DOT format string
"""
lines = [
f'digraph "{title}" {{',
" rankdir=LR;",
f' label="{title}";',
" node [shape=box];",
]
# Add nodes
for node in sorted(graph.nodes):
safe_id = node.replace("-", "_")
lines.append(f' {safe_id} [label="{node}"];')
# Add edges
for source in sorted(graph.nodes):
for target in sorted(graph.get_successors(source)):
edge_type = graph.get_edge_type(source, target)
style = _DOT_EDGE_STYLES.get(edge_type, 'style="solid"')
safe_source = source.replace("-", "_")
safe_target = target.replace("-", "_")
label = edge_type.value if edge_type else "requires"
lines.append(
f' {safe_source} -> {safe_target} [{style} label="{label}"];'
)
lines.append("}")
return "\n".join(lines)
@staticmethod
def to_mermaid(graph: DependencyGraph, title: str = "Dependencies") -> str:
"""
Export dependency graph to Mermaid diagram format.
Args:
graph: DependencyGraph to export
title: Graph title (used as comment)
Returns:
Mermaid format string
"""
lines = [
f"%%{{ title: {title} }}%%",
"graph LR",
]
# Add edges
edges_added = False
for source in sorted(graph.nodes):
for target in sorted(graph.get_successors(source)):
edge_type = graph.get_edge_type(source, target)
arrow = _MERMAID_EDGE_STYLES.get(edge_type, "-->")
label = edge_type.value if edge_type else "requires"
lines.append(f" {source}{arrow}|{label}|{target}")
edges_added = True
# Add isolated nodes (no edges)
if not edges_added:
for node in sorted(graph.nodes):
lines.append(f" {node}")
else:
# Add any isolated nodes that have no edges
connected = set()
for source in graph.nodes:
if graph.get_successors(source) or graph.get_predecessors(source):
connected.add(source)
for node in sorted(graph.nodes - connected):
lines.append(f" {node}")
return "\n".join(lines)