Skip to content

UML System Model

The diagrams on this page provide a structural and behavioral picture of structure_parser at different levels of abstraction. The component diagram shows subsystem boundaries and dependencies, the sequence diagrams show runtime message flows, and the class diagrams show the contract object graphs that carry data between subsystems.

Component Diagram

The component diagram below shows the major subsystems of structure_parser and the dependencies between them. The CLI and Python API are the two entry points; both delegate immediately to the Orchestrator, which coordinates all other subsystems. The Orchestrator never calls adapters, enrichment steps, or validators directly — it goes through the registry and pipeline objects that own those responsibilities.

graph LR
    subgraph "Entry Points"
        CLI["CLI\ncommands.py"]
        API["Python API\norchestrator.py"]
    end

    subgraph "Application"
        ORCH["Orchestrator\norchestrator.py"]
    end

    subgraph "Adapters"
        REG["AdapterRegistry"]
        MD["MarkdownAdapter\nmarkdown-it-py"]
        HTML["HTMLAdapter\nlxml"]
    end

    subgraph "Enrichment"
        SE["SemanticEnricher"]
        ME["MetadataExtractor"]
        SB["StructureBuilder"]
        RC["ReferenceClassifier"]
        LFR["LocalFileResolver"]
    end

    subgraph "Classification"
        CLS["StructuredMarkdownClassifier\nclassifier.py"]
        CM["ComponentMapper"]
        AM["AttributeMapper"]
    end

    subgraph "Validation"
        VAL["SchemaValidator\nDraft7Validator"]
        SR["SchemaRepository"]
    end

    subgraph "Readiness"
        RE["ReadinessEvaluator"]
        DITA["DitaReadinessEvaluator"]
        SORG["SchemaOrgReadinessEvaluator"]
        RAG["RagIngestionReadinessEvaluator"]
    end

    subgraph "Repositories"
        SRCR["SourceRepository"]
    end

    subgraph "Reporting"
        DR["DiagnosticReporter"]
        STR["StructureReporter"]
        MR["ModelReporter"]
    end

    subgraph "Repository Pipeline"
        PORCH["PipelineOrchestrator"]
        DISC["MarkdownDiscoveryService"]
        OUT["ParsedDocumentWriter"]
        CSV["CsvInventoryReporter"]
    end

    CLI --> ORCH
    API --> ORCH
    ORCH --> REG
    ORCH --> SE
    ORCH --> CLS
    ORCH --> VAL
    ORCH --> RE
    ORCH --> SRCR
    ORCH --> DR
    ORCH --> STR
    ORCH --> MR
    CLI --> PORCH
    PORCH --> DISC
    PORCH --> ORCH
    PORCH --> OUT
    CLI --> CSV
    REG --> MD
    REG --> HTML
    SE --> ME
    SE --> SB
    SE --> RC
    SE --> LFR
    CLS --> CM
    CLS --> AM
    VAL --> SR
    RE --> DITA
    RE --> SORG
    RE --> RAG

The Repositories subsystem (SourceRepository, SchemaRepository) handles parser file I/O. Adapters receive source bytes from SourceRepository rather than reading files directly, which keeps adapters testable with in-memory strings. SchemaRepository pre-loads all JSON schemas at startup and hands the pre-built schema store to SchemaValidator, eliminating repeated file reads during batch processing.

The Repository Pipeline subsystem handles repository-scale operations. It discovers Markdown files, delegates each file to the parser orchestrator, writes parsed JSON output, and writes the CSV inventory report through the CLI command.

Sequence Diagram

The sequence diagram below shows the complete message flow for a call to parse_file("my-article.md") through the Python API. Each vertical lifeline represents one object; each arrow represents one method call or return value.

sequenceDiagram
    participant Caller
    participant Orchestrator
    participant AdapterRegistry
    participant MarkdownAdapter
    participant SemanticEnricher
    participant MetadataExtractor
    participant StructureBuilder
    participant ReferenceClassifier
    participant StructuredMarkdownClassifier
    participant SchemaValidator
    participant ReadinessEvaluator

    Caller->>Orchestrator: parse_file("my-article.md", config)
    Orchestrator->>AdapterRegistry: get_adapter("markdown")
    AdapterRegistry-->>Orchestrator: MarkdownAdapter
    Orchestrator->>MarkdownAdapter: parse(source_bytes, path)
    MarkdownAdapter-->>Orchestrator: RawParseModel

    Orchestrator->>SemanticEnricher: enrich(raw_model, config)
    SemanticEnricher->>MetadataExtractor: extract(raw_model)
    MetadataExtractor-->>SemanticEnricher: metadata + diagnostics
    SemanticEnricher->>StructureBuilder: build(raw_model)
    StructureBuilder-->>SemanticEnricher: DocumentStructure + diagnostics
    SemanticEnricher->>ReferenceClassifier: classify(raw_model)
    ReferenceClassifier-->>SemanticEnricher: list[Reference] + diagnostics
    SemanticEnricher-->>Orchestrator: partial ParsedDocument fields

    Orchestrator->>StructuredMarkdownClassifier: classify(raw_model, metadata)
    StructuredMarkdownClassifier-->>Orchestrator: StructuredContent + diagnostics

    Orchestrator->>SchemaValidator: validate(structured_content, config)
    SchemaValidator-->>Orchestrator: ModelValidationResult + diagnostics

    Orchestrator->>ReadinessEvaluator: evaluate(parsed_document)
    ReadinessEvaluator-->>Orchestrator: TransformReadiness + diagnostics

    Orchestrator-->>Caller: ParsedDocument

The orchestrator is the only component that sees all five layer outputs simultaneously. It assembles them into a single ParsedDocument at the end, merging all diagnostics from every layer into ParsedDocument.diagnostics. This assembly step is the only place in the codebase where cross-layer data is combined; every other component operates on its own input contract in isolation.

Class Diagram

The class diagram below shows the parser contract object graph. It is the authoritative picture of how ParsedDocument — the parser's primary output — relates to every other contract type. Cardinalities on association lines indicate how many instances of the target type a source instance may carry.

classDiagram
    class ParsedDocument {
        +schema_version: str
        +source_path: str
        +source_format: str
        +metadata: dict
        +title: str
        +has_errors: bool
        +error_count: int
        +warning_count: int
    }

    class DocumentProvenance {
        +content_hash: str
        +parse_timestamp: str
        +adapter_version: str
        +schema_version: str
    }

    class DocumentStructure {
        +headings: list
    }

    class StructuredContent {
        +article_type: str
        +units: list[Unit]
    }

    class Unit {
        +unit_type: str
        +title: str
        +source_span: SourceSpan
    }

    class Component {
        +component_type: str
        +content: str
        +source_span: SourceSpan
    }

    class Attribute {
        +attribute_type: str
        +content: str
    }

    class Reference {
        +ref_type: str
        +href: str
        +text: str
        +state: str
        +resolved_path: str
    }

    class Diagnostic {
        +code: str
        +severity: str
        +category: str
        +message: str
        +remediation: str
        +start_line: int
        +end_line: int
    }

    class ModelValidationResult {
        +schema_id: str
        +valid: bool
        +source_path: str
        +diagnostics: list[Diagnostic]
    }

    class TransformReadiness {
        +targets: list[TargetReadiness]
    }

    class TargetReadiness {
        +target: str
        +status: str
        +reasons: list[str]
        +missing: list[str]
    }

    class ParseRunResult {
        +documents: list[ParsedDocument]
        +run_diagnostics: list[Diagnostic]
        +success: bool
    }

    class ParseStats {
        +total_files: int
        +success_count: int
        +error_count: int
        +elapsed_seconds: float
    }

    class SourceSpan {
        +source_path: str
        +start_line: int
        +end_line: int
        +provenance_status: str
    }

    ParsedDocument "1" --> "1" DocumentProvenance : provenance
    ParsedDocument "1" --> "1" DocumentStructure : structure
    ParsedDocument "1" --> "0..1" StructuredContent : structured_content
    ParsedDocument "1" --> "0..*" Reference : references
    ParsedDocument "1" --> "0..*" Diagnostic : diagnostics
    ParsedDocument "1" --> "0..1" ModelValidationResult : validation
    ParsedDocument "1" --> "0..1" TransformReadiness : readiness
    StructuredContent "1" --> "0..*" Unit : units
    Unit "1" --> "0..*" Component : components
    Unit "1" --> "1" SourceSpan : source_span
    Component "1" --> "0..*" Attribute : attributes
    Component "1" --> "1" SourceSpan : source_span
    TransformReadiness "1" --> "1..*" TargetReadiness : targets
    ParseRunResult "1" --> "0..*" ParsedDocument : documents
    ParseRunResult "1" --> "1" ParseStats : stats

The class diagram reveals a key structural property of the design: ParsedDocument is the single root of the entire output graph. There is no other way for a caller to obtain a StructuredContent, TransformReadiness, or ModelValidationResult except through a ParsedDocument. This means callers always have full context available — they never hold a validation result without the document it came from, and they never hold a readiness assessment without the diagnostics that explain it.

Repository Pipeline Sequence Diagram

The repository pipeline sequence diagram shows the runtime message flow for structure-parser pipe. The CLI command owns CSV report writing, while PipelineOrchestrator owns discovery, parser calls, JSON output writing, and run statistics.

sequenceDiagram
    actor User
    participant CLI as cmd_pipe
    participant Cmd as PipelineCommand
    participant Orch as PipelineOrchestrator
    participant Disc as MarkdownDiscoveryService
    participant Parser as parse_one
    participant Writer as ParsedDocumentWriter
    participant CSV as CsvInventoryReporter

    User->>CLI: structure-parser pipe INPUT --out OUTPUT
    CLI->>Cmd: run(PipelineConfig)
    Cmd->>Orch: run(config)
    Orch->>Disc: discover(config)
    Disc-->>Orch: DiscoveredSource[] + diagnostics
    loop each discovered source
        Orch->>Parser: parse_one(source_path, parser_config)
        Parser-->>Orch: ParsedDocument
        Orch->>Writer: write(document, target_path, dry_run)
        Writer-->>Orch: PIPE-005 or success
    end
    Orch-->>Cmd: PipelineRunResult
    Cmd->>CSV: write(result, report_path)
    CSV-->>Cmd: PIPE-003 or success
    Cmd-->>CLI: summary text + exit code

The pipeline sequence makes the boundary with the parser explicit. The parser decides article, unit, component, attribute, and information types; the pipeline only schedules files and preserves those parser results.

Repository Pipeline Class Diagram

The repository pipeline class diagram shows the operational contracts added for folder-scale processing. These contracts describe run state and file routing rather than structured content semantics.

classDiagram
    class PipelineConfig {
        +inputs: list[Path]
        +output_dir: Path
        +report_path: Path
        +include_patterns: list[str]
        +exclude_patterns: list[str]
        +log_file: Path
        +log_format: str
        +strict: bool
        +dry_run: bool
    }

    class DiscoveredSource {
        +source_root: Path
        +source_path: Path
        +relative_path: Path
        +source_format: SourceFormat
    }

    class PipelineFileResult {
        +source: DiscoveredSource
        +target_path: Path
        +status: PipelineFileStatus
        +parser_codes: list[str]
        +pipeline_code: str
        +error_count: int
        +warning_count: int
        +duration_ms: float
    }

    class PipelineRunStats {
        +discovered_count: int
        +parsed_count: int
        +failed_count: int
        +skipped_count: int
        +error_count: int
        +warning_count: int
        +duration_ms: float
    }

    class PipelineRunResult {
        +schema_version: str
        +run_id: str
        +files: list[PipelineFileResult]
        +run_diagnostics: list[Diagnostic]
        +stats: PipelineRunStats
    }

    PipelineRunResult "1" --> "0..*" PipelineFileResult : files
    PipelineRunResult "1" --> "1" PipelineRunStats : stats
    PipelineFileResult "1" --> "1" DiscoveredSource : source

The pipeline class diagram shows why pipeline contracts should remain operational. The graph references parser diagnostics but does not include Article, Unit, Component, or Attribute classes because those belong to the parser/model contract graph.