Coverage for little_loops / dependency_mapper / models.py: 100%

41 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2026-05-22 16:19 -0500

1"""Dependency mapper data models. 

2 

3Dataclasses for cross-issue dependency discovery and validation. 

4""" 

5 

6from __future__ import annotations 

7 

8from dataclasses import dataclass, field 

9 

10 

11@dataclass 

12class DependencyProposal: 

13 """A proposed dependency relationship between two issues. 

14 

15 Attributes: 

16 source_id: Issue that would be blocked 

17 target_id: Issue that would block (the blocker) 

18 reason: Category of discovery method 

19 confidence: Score from 0.0 to 1.0 

20 rationale: Human-readable explanation 

21 overlapping_files: Files referenced by both issues 

22 conflict_score: Semantic conflict score from 0.0 to 1.0 

23 """ 

24 

25 source_id: str 

26 target_id: str 

27 reason: str 

28 confidence: float 

29 rationale: str 

30 overlapping_files: list[str] = field(default_factory=list) 

31 conflict_score: float = 0.5 

32 

33 

34@dataclass 

35class ParallelSafePair: 

36 """A pair of issues that share files but can safely run in parallel. 

37 

38 Attributes: 

39 issue_a: First issue ID 

40 issue_b: Second issue ID 

41 shared_files: Files referenced by both issues 

42 conflict_score: Semantic conflict score (< 0.4) 

43 reason: Why these are parallel-safe 

44 """ 

45 

46 issue_a: str 

47 issue_b: str 

48 shared_files: list[str] = field(default_factory=list) 

49 conflict_score: float = 0.0 

50 reason: str = "" 

51 

52 

53@dataclass 

54class ValidationResult: 

55 """Result of validating existing dependency references. 

56 

57 Attributes: 

58 broken_refs: (issue_id, missing_ref_id) pairs for broken blocked_by refs 

59 missing_backlinks: (issue_id, should_have_backlink_from) pairs 

60 cycles: Cycle paths from DependencyGraph.detect_cycles() 

61 stale_completed_refs: (issue_id, completed_ref_id) pairs 

62 broken_depends_on_refs: (issue_id, missing_ref_id) pairs for broken depends_on refs 

63 broken_relates_to_refs: (issue_id, missing_ref_id) pairs for broken relates_to refs 

64 """ 

65 

66 broken_refs: list[tuple[str, str]] = field(default_factory=list) 

67 missing_backlinks: list[tuple[str, str]] = field(default_factory=list) 

68 cycles: list[list[str]] = field(default_factory=list) 

69 stale_completed_refs: list[tuple[str, str]] = field(default_factory=list) 

70 broken_depends_on_refs: list[tuple[str, str]] = field(default_factory=list) 

71 broken_relates_to_refs: list[tuple[str, str]] = field(default_factory=list) 

72 

73 @property 

74 def has_issues(self) -> bool: 

75 """Return True if any validation problems were found.""" 

76 return bool( 

77 self.broken_refs 

78 or self.missing_backlinks 

79 or self.cycles 

80 or self.stale_completed_refs 

81 or self.broken_depends_on_refs 

82 or self.broken_relates_to_refs 

83 ) 

84 

85 

86@dataclass 

87class DependencyReport: 

88 """Complete dependency analysis report. 

89 

90 Attributes: 

91 proposals: Proposed new dependency relationships 

92 parallel_safe: Pairs of issues that share files but can run in parallel 

93 validation: Validation results for existing dependencies 

94 issue_count: Total issues analyzed 

95 existing_dep_count: Number of existing dependency edges 

96 """ 

97 

98 proposals: list[DependencyProposal] = field(default_factory=list) 

99 parallel_safe: list[ParallelSafePair] = field(default_factory=list) 

100 validation: ValidationResult = field(default_factory=ValidationResult) 

101 issue_count: int = 0 

102 existing_dep_count: int = 0 

103 

104 

105@dataclass 

106class FixResult: 

107 """Result of auto-fixing dependency validation issues. 

108 

109 Attributes: 

110 changes: Human-readable descriptions of each fix applied 

111 modified_files: Set of file paths that were modified 

112 skipped_cycles: Number of cycles skipped (out of scope for auto-fix) 

113 """ 

114 

115 changes: list[str] = field(default_factory=list) 

116 modified_files: set[str] = field(default_factory=set) 

117 skipped_cycles: int = 0