Coverage for backend/django/diagnostics/failure_bundle.py: 100%

32 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-02-12 01:47 +0000

1"""Failure bundle types using Pydantic for validation and serialization in orchestrator.""" 

2 

3from __future__ import annotations 

4 

5from typing import Optional 

6 

7from pydantic import BaseModel, Field, JsonValue 

8 

9 

10class SolverMeta(BaseModel): 

11 termination_condition: Optional[str] = None 

12 solver_status: Optional[str] = None 

13 exception: Optional[str] = None 

14 

15 

16class VariableOutsideBounds(BaseModel): 

17 """ 

18 A single variable reported outside bounds by DiagnosticsToolbox. 

19 

20 This is intentionally a small, stable schema: it’s meant to be evidence we 

21 can show in the UI and use for lightweight suggestions. (output is roughly parsed based on outputs seen in docs )  

22 """ 

23 

24 name: str 

25 value: float | str | None = None 

26 lower: float | str | None = None 

27 upper: float | str | None = None 

28 reason: str = "fixed_outside_bounds" 

29 

30 

31class StructuralSignals(BaseModel): 

32 dof: Optional[int] = None 

33 overconstrained: JsonValue | None = None 

34 underconstrained: JsonValue | None = None 

35 inconsistent_units: list[JsonValue] | None = None 

36 

37 

38class NumericalSignals(BaseModel): 

39 variables_outside_bounds: list[VariableOutsideBounds] | None = None 

40 constraints_large_residuals: list[JsonValue] | None = None 

41 scaling_warnings: list[JsonValue] | None = None 

42 

43class FailureBundle(BaseModel): 

44 task_id: int 

45 flowsheet_id: int 

46 solve_index: Optional[int] = None 

47 trigger: str = "solve_failure" 

48 

49 # Upstream payloads may omit solver metadata. Default it so `bundle.solver` is always present. 

50 solver: SolverMeta = Field(default_factory=SolverMeta) 

51 

52 # Short, high-level error messages (if any). This is separate from `diagnostics_raw_text`. 

53 eval_errors: Optional[list[str]] = None 

54 

55 # Raw DiagnosticsToolbox output as plain text (not structured JSON). 

56 # Optional: some failure paths don't capture the toolbox report. 

57 diagnostics_raw_text: Optional[str] = None 

58 

59 structural: StructuralSignals = Field(default_factory=StructuralSignals) 

60 numerical: NumericalSignals = Field(default_factory=NumericalSignals)