flowchart TD
  user([User])
  yaml["check.yaml<br>missing block with metric and mustBeLessThanOrEqual"]
  user -- types or hovers --> yaml

  subgraph extension["VS Code extension"]
    panel["TuneCheckPanel"]
    renderer["failuresAllowedRenderer"]
    quickpicks["failuresAllowedQuickPicks<br>and percent variant"]
    panel --> renderer
    renderer --> quickpicks
  end

  subgraph lsp["LSP server"]
    hoverHandler["Hover handler"]
    hoverService["HoverService"]
    metricHint["resolve_metric_hint"]
    thresholdHint["resolve_threshold_hint"]
    family["ThresholdFamily.hover_for<br>and metric_hover"]
    tuneService["TuneCheckService"]
    yamlEditor["yaml_editor.format_flat_yaml"]

    hoverHandler --> hoverService
    hoverService --> metricHint
    hoverService --> thresholdHint
    metricHint --> family
    thresholdHint --> family
    tuneService --> yamlEditor
  end

  user -- hover on metric or mustBe --> hoverHandler
  user -- click Pick threshold --> panel
  panel -- prepareSession --> tuneService
  tuneService -- TuningSession with metricMode --> panel
  panel -- applyEdit with draftConfig.metric --> tuneService
  tuneService -- writes metric and mustBe --> yaml
sequenceDiagram
  participant U as User
  participant P as TuneCheckPanel
  participant R as failuresAllowedRenderer
  participant L as LSP server
  participant T as TuneCheckService
  participant H as HoverService
  participant F as ThresholdFamily

  U->>P: open Pick Threshold
  P->>L: prepareSession
  L->>T: prepare_session
  T-->>L: TuningSession with metricMode and metricSupported
  L-->>P: session
  P->>R: renderBody with session
  R-->>P: HTML with metric toggle and quick-picks
  P-->>U: panel rendered

  U->>R: toggle to percent
  R->>R: switch quick-picks to percent variant
  U->>P: click Apply
  P->>L: applyEdit with draftConfig metric percent
  L->>T: apply_edit
  T->>T: format_flat_yaml emits metric percent and mustBe
  T-->>L: applied
  L-->>P: applied banner

  U->>L: hover on metric key
  L->>H: hover_yaml
  H->>H: resolve_metric_hint
  H->>F: metric_hover for FAILURES_ALLOWED
  F-->>H: prose with empty-scope rule
  H-->>L: HoverInfo
  L-->>U: rendered Markdown

  U->>L: hover on mustBeLessThanOrEqual
  L->>H: hover_yaml
  H->>H: resolve_threshold_hint
  H->>F: hover_for key MUST_BE_LESS_THAN_OR_EQUAL metric_mode percent
  F-->>H: prose Failures allowed five percent
  H-->>L: HoverInfo
  L-->>U: rendered Markdown
classDiagram
  class MetricMode {
    <<Literal>>
  }

  class ThresholdFamily {
    <<StrEnum>>
    +hover_for(key, metric_mode) str
    +metric_hover() str
  }

  class CheckBlock {
    <<dataclass>>
    +check_type: str
    +column: str
    +schema_name: str
    +check_name: str
    +metric_mode: MetricMode
  }

  class ThresholdHint {
    <<dataclass>>
    +family: ThresholdFamily
    +key: MustBeKey
    +check_type: str
    +column: str
    +metric_mode: MetricMode
    +prose: str
  }

  class MetricHint {
    <<dataclass>>
    +family: ThresholdFamily
    +check_type: str
    +metric_mode: MetricMode
    +prose: str
  }

  class HoverService {
    +hover_yaml(query, sink) HoverInfo
  }

  class TuningSession {
    <<dataclass>>
    +family: ThresholdFamily
    +metric_mode: MetricMode
    +metric_supported: bool
  }

  class FlatThresholdConfig {
    <<dataclass>>
    +value: float
    +operator: ThresholdOperator
    +metric: MetricMode
  }

  class FailuresAllowedRenderer {
    <<TS>>
    +renderBody(ctx) str
  }

  HoverService --> ThresholdHint
  HoverService --> MetricHint
  ThresholdHint --> ThresholdFamily
  MetricHint --> ThresholdFamily
  ThresholdHint --> CheckBlock
  TuningSession --> ThresholdFamily
  FailuresAllowedRenderer --> TuningSession
  FlatThresholdConfig --> MetricMode