///|
/// Explains why a caller proposes a text replacement.
pub(all) enum RomanEditReason {
  RomanCanonicalizationEdit
  RomanCaseNormalizationEdit
  RomanUnicodeExpansionEdit
  RomanLintDiagnosticEdit(DiagnosticCode)
  CallerRequestedEdit(String)
} derive(Eq, Debug)

///|
/// Describes one caller-identified replacement over a half-open source span.
pub(all) struct RomanTextEdit {
  id : String
  span : SourceSpan
  expected_source : String
  replacement : String
  numeric_value : Int?
  reason : RomanEditReason
  source_diagnostic_code : DiagnosticCode?
} derive(Eq, Debug)

///|
/// Bounds the complete output projected by a validated edit plan.
pub(all) struct RomanEditPlanConfig {
  max_projected_length : Int64
} derive(Eq, Debug)

///|
/// Summarizes the character-level size effects of a validated plan.
pub(all) struct RomanEditPlanStatistics {
  edit_count : Int
  source_length : Int64
  unchanged_segment_count : Int
  removed_length : Int64
  inserted_length : Int64
  projected_length : Int64
} derive(Eq, Debug)

///|
/// Retains source-ordered edits and reproducible size statistics.
pub(all) struct RomanEditPlan {
  original : String
  config : RomanEditPlanConfig
  edits : Array[RomanTextEdit]
  statistics : RomanEditPlanStatistics
  diagnostics : Array[RomanDiagnostic]
} derive(Eq, Debug)

///|
/// Reports the first invalid condition under the documented validation order.
pub(all) enum RomanEditError {
  InvalidRomanProjectedOutputLimit(Int64)
  EmptyRomanEditId(Int)
  DuplicateRomanEditId(String)
  NegativeRomanEditSpan(String, SourceSpan)
  ReversedRomanEditSpan(String, SourceSpan)
  RomanEditSpanOutOfBounds(String, SourceSpan, Int)
  OverlappingRomanEdits(String, String)
  RomanEditSourceMismatch(String, String, String)
  NoOpRomanEdit(String)
  RomanProjectedOutputNotRepresentable(Int64, Int64)
  RomanProjectedOutputLimitExceeded(Int64, Int64)
  RomanEditPlanSourceMismatch(String, String)
  RomanEditDocumentLintFailed(ConfigError)
  RomanEditRewriteFailed(RomanRewriteError)
} derive(Eq, Debug)