|
| 1 | +package link.socket.kore.agents.events.tickets |
| 2 | + |
| 3 | +/** |
| 4 | + * Represents the type of escalation needed for a blocker. |
| 5 | + * Each escalation type defines what kind of issue it is and how it should be resolved. |
| 6 | + * |
| 7 | + * This hierarchy is designed to be used with LLM classification - an LLM analyzes |
| 8 | + * a blocker scenario and categorizes it into the appropriate escalation type. |
| 9 | + */ |
| 10 | +sealed class Escalation { |
| 11 | + |
| 12 | + /** |
| 13 | + * The process mechanism used to resolve this type of escalation. |
| 14 | + */ |
| 15 | + abstract val process: EscalationProcess |
| 16 | + |
| 17 | + /** |
| 18 | + * Human-readable description of this escalation type for LLM context. |
| 19 | + */ |
| 20 | + abstract val description: String |
| 21 | + |
| 22 | + // ==================== Discussion Escalations ==================== |
| 23 | + |
| 24 | + /** |
| 25 | + * Escalations that require collaborative discussion to resolve. |
| 26 | + * These typically involve technical topics where multiple perspectives |
| 27 | + * help reach a better solution. |
| 28 | + */ |
| 29 | + sealed class Discussion : Escalation() { |
| 30 | + |
| 31 | + /** |
| 32 | + * Code needs review before proceeding. |
| 33 | + * Includes pull requests, implementation approaches, and code quality concerns. |
| 34 | + */ |
| 35 | + data object CodeReview : Discussion() { |
| 36 | + override val process = EscalationProcess.AgentMeeting |
| 37 | + override val description = "Code needs review - includes PRs, implementation approaches, and quality concerns" |
| 38 | + } |
| 39 | + |
| 40 | + /** |
| 41 | + * Design decisions need discussion. |
| 42 | + * Includes UI/UX design, API design, and system design choices. |
| 43 | + */ |
| 44 | + data object Design : Discussion() { |
| 45 | + override val process = EscalationProcess.AgentMeeting |
| 46 | + override val description = "Design decisions needed - UI/UX, API design, or system design choices" |
| 47 | + } |
| 48 | + |
| 49 | + /** |
| 50 | + * Architecture questions need clarification. |
| 51 | + * Includes system structure, component relationships, and technical patterns. |
| 52 | + */ |
| 53 | + data object Architecture : Discussion() { |
| 54 | + override val process = EscalationProcess.AgentMeeting |
| 55 | + override val description = "Architecture clarification needed - system structure, components, or patterns" |
| 56 | + } |
| 57 | + |
| 58 | + /** |
| 59 | + * Requirements need clarification or refinement. |
| 60 | + * Includes unclear specifications, missing details, or conflicting requirements. |
| 61 | + */ |
| 62 | + data object Requirements : Discussion() { |
| 63 | + override val process = EscalationProcess.HumanMeeting |
| 64 | + override val description = "Requirements clarification needed - unclear specs, missing details, or conflicts" |
| 65 | + } |
| 66 | + } |
| 67 | + |
| 68 | + // ==================== Decision Escalations ==================== |
| 69 | + |
| 70 | + /** |
| 71 | + * Escalations that require a decision to be made. |
| 72 | + * These block progress until someone with authority makes a choice. |
| 73 | + */ |
| 74 | + sealed class Decision : Escalation() { |
| 75 | + |
| 76 | + /** |
| 77 | + * Technical decision needed between alternatives. |
| 78 | + * Includes technology choices, library selection, and implementation strategies. |
| 79 | + */ |
| 80 | + data object Technical : Decision() { |
| 81 | + override val process = EscalationProcess.AgentMeeting |
| 82 | + override val description = "Technical decision needed - technology choices, libraries, or implementation strategies" |
| 83 | + } |
| 84 | + |
| 85 | + /** |
| 86 | + * Product decision needed from stakeholders. |
| 87 | + * Includes feature direction, user experience choices, and business logic decisions. |
| 88 | + */ |
| 89 | + data object Product : Decision() { |
| 90 | + override val process = EscalationProcess.HumanMeeting |
| 91 | + override val description = "Product decision needed - feature direction, UX choices, or business logic" |
| 92 | + } |
| 93 | + |
| 94 | + /** |
| 95 | + * Authorization or approval needed to proceed. |
| 96 | + * Includes security approvals, compliance sign-offs, and access grants. |
| 97 | + */ |
| 98 | + data object Authorization : Decision() { |
| 99 | + override val process = EscalationProcess.HumanApproval |
| 100 | + override val description = "Authorization needed - security approvals, compliance, or access grants" |
| 101 | + } |
| 102 | + } |
| 103 | + |
| 104 | + // ==================== Budget Escalations ==================== |
| 105 | + |
| 106 | + /** |
| 107 | + * Escalations related to budget, resources, or costs. |
| 108 | + * These typically require human approval due to financial implications. |
| 109 | + */ |
| 110 | + sealed class Budget : Escalation() { |
| 111 | + |
| 112 | + /** |
| 113 | + * Resource allocation decision needed. |
| 114 | + * Includes team capacity, infrastructure resources, and tool licenses. |
| 115 | + */ |
| 116 | + data object ResourceAllocation : Budget() { |
| 117 | + override val process = EscalationProcess.HumanMeeting |
| 118 | + override val description = "Resource allocation needed - team capacity, infrastructure, or licenses" |
| 119 | + } |
| 120 | + |
| 121 | + /** |
| 122 | + * Cost approval needed for expenditure. |
| 123 | + * Includes service costs, tool purchases, and infrastructure expenses. |
| 124 | + */ |
| 125 | + data object CostApproval : Budget() { |
| 126 | + override val process = EscalationProcess.HumanApproval |
| 127 | + override val description = "Cost approval needed - service costs, purchases, or infrastructure expenses" |
| 128 | + } |
| 129 | + |
| 130 | + /** |
| 131 | + * Timeline or deadline negotiation needed. |
| 132 | + * Includes scope-timeline tradeoffs and delivery date discussions. |
| 133 | + */ |
| 134 | + data object Timeline : Budget() { |
| 135 | + override val process = EscalationProcess.HumanMeeting |
| 136 | + override val description = "Timeline negotiation needed - scope-timeline tradeoffs or delivery dates" |
| 137 | + } |
| 138 | + } |
| 139 | + |
| 140 | + // ==================== Priorities Escalations ==================== |
| 141 | + |
| 142 | + /** |
| 143 | + * Escalations related to prioritization and scheduling. |
| 144 | + * These involve deciding what to work on and in what order. |
| 145 | + */ |
| 146 | + sealed class Priorities : Escalation() { |
| 147 | + |
| 148 | + /** |
| 149 | + * Conflicting priorities need resolution. |
| 150 | + * Includes competing deadlines, resource conflicts, and dependency ordering. |
| 151 | + */ |
| 152 | + data object Conflict : Priorities() { |
| 153 | + override val process = EscalationProcess.HumanMeeting |
| 154 | + override val description = "Priority conflict - competing deadlines, resource conflicts, or dependency ordering" |
| 155 | + } |
| 156 | + |
| 157 | + /** |
| 158 | + * Reprioritization request for existing work. |
| 159 | + * Includes urgent requests, changed business needs, and blocking issues. |
| 160 | + */ |
| 161 | + data object Reprioritization : Priorities() { |
| 162 | + override val process = EscalationProcess.HumanApproval |
| 163 | + override val description = "Reprioritization request - urgent requests, changed needs, or blocking issues" |
| 164 | + } |
| 165 | + |
| 166 | + /** |
| 167 | + * Dependency on another team or project. |
| 168 | + * Includes cross-team coordination and external project dependencies. |
| 169 | + */ |
| 170 | + data object Dependency : Priorities() { |
| 171 | + override val process = EscalationProcess.AgentMeeting |
| 172 | + override val description = "Cross-team dependency - coordination with other teams or projects" |
| 173 | + } |
| 174 | + } |
| 175 | + |
| 176 | + // ==================== Scope Escalations ==================== |
| 177 | + |
| 178 | + /** |
| 179 | + * Escalations related to project scope and boundaries. |
| 180 | + * These affect what is and isn't included in the work. |
| 181 | + */ |
| 182 | + sealed class Scope : Escalation() { |
| 183 | + |
| 184 | + /** |
| 185 | + * Scope expansion or feature creep detected. |
| 186 | + * Includes additional requirements, expanded functionality, and new use cases. |
| 187 | + */ |
| 188 | + data object Expansion : Scope() { |
| 189 | + override val process = EscalationProcess.HumanMeeting |
| 190 | + override val description = "Scope expansion detected - additional requirements or new use cases" |
| 191 | + } |
| 192 | + |
| 193 | + /** |
| 194 | + * Scope reduction or feature cut needed. |
| 195 | + * Includes timeline pressure, technical limitations, and resource constraints. |
| 196 | + */ |
| 197 | + data object Reduction : Scope() { |
| 198 | + override val process = EscalationProcess.HumanMeeting |
| 199 | + override val description = "Scope reduction needed - timeline pressure or resource constraints" |
| 200 | + } |
| 201 | + |
| 202 | + /** |
| 203 | + * Scope boundaries unclear or undefined. |
| 204 | + * Includes ambiguous requirements and undefined edge cases. |
| 205 | + */ |
| 206 | + data object Clarification : Scope() { |
| 207 | + override val process = EscalationProcess.HumanMeeting |
| 208 | + override val description = "Scope clarification needed - ambiguous requirements or undefined boundaries" |
| 209 | + } |
| 210 | + } |
| 211 | + |
| 212 | + // ==================== External Escalations ==================== |
| 213 | + |
| 214 | + /** |
| 215 | + * Escalations caused by external factors outside the team's control. |
| 216 | + */ |
| 217 | + sealed class External : Escalation() { |
| 218 | + |
| 219 | + /** |
| 220 | + * Waiting for third-party vendor or service. |
| 221 | + * Includes API availability, support responses, and service provisioning. |
| 222 | + */ |
| 223 | + data object Vendor : External() { |
| 224 | + override val process = EscalationProcess.ExternalDependency |
| 225 | + override val description = "Waiting for vendor - API availability, support, or service provisioning" |
| 226 | + } |
| 227 | + |
| 228 | + /** |
| 229 | + * Waiting for customer or end-user input. |
| 230 | + * Includes user testing feedback, customer requirements, and stakeholder input. |
| 231 | + */ |
| 232 | + data object Customer : External() { |
| 233 | + override val process = EscalationProcess.HumanApproval |
| 234 | + override val description = "Waiting for customer - user feedback, requirements, or stakeholder input" |
| 235 | + } |
| 236 | + } |
| 237 | + |
| 238 | + companion object { |
| 239 | + /** |
| 240 | + * Returns all possible escalation types for LLM classification context. |
| 241 | + * The LLM uses these descriptions to categorize blocker scenarios. |
| 242 | + */ |
| 243 | + fun allTypes(): List<Escalation> = listOf( |
| 244 | + // Discussion |
| 245 | + Discussion.CodeReview, |
| 246 | + Discussion.Design, |
| 247 | + Discussion.Architecture, |
| 248 | + Discussion.Requirements, |
| 249 | + // Decision |
| 250 | + Decision.Technical, |
| 251 | + Decision.Product, |
| 252 | + Decision.Authorization, |
| 253 | + // Budget |
| 254 | + Budget.ResourceAllocation, |
| 255 | + Budget.CostApproval, |
| 256 | + Budget.Timeline, |
| 257 | + // Priorities |
| 258 | + Priorities.Conflict, |
| 259 | + Priorities.Reprioritization, |
| 260 | + Priorities.Dependency, |
| 261 | + // Scope |
| 262 | + Scope.Expansion, |
| 263 | + Scope.Reduction, |
| 264 | + Scope.Clarification, |
| 265 | + // External |
| 266 | + External.Vendor, |
| 267 | + External.Customer, |
| 268 | + ) |
| 269 | + |
| 270 | + /** |
| 271 | + * Returns a formatted string of all escalation types and their descriptions |
| 272 | + * suitable for use in LLM prompts. |
| 273 | + */ |
| 274 | + fun allTypesForPrompt(): String = buildString { |
| 275 | + appendLine("Available escalation types:") |
| 276 | + appendLine() |
| 277 | + |
| 278 | + appendLine("## Discussion") |
| 279 | + appendLine("- CodeReview: ${Discussion.CodeReview.description}") |
| 280 | + appendLine("- Design: ${Discussion.Design.description}") |
| 281 | + appendLine("- Architecture: ${Discussion.Architecture.description}") |
| 282 | + appendLine("- Requirements: ${Discussion.Requirements.description}") |
| 283 | + appendLine() |
| 284 | + |
| 285 | + appendLine("## Decision") |
| 286 | + appendLine("- Technical: ${Decision.Technical.description}") |
| 287 | + appendLine("- Product: ${Decision.Product.description}") |
| 288 | + appendLine("- Authorization: ${Decision.Authorization.description}") |
| 289 | + appendLine() |
| 290 | + |
| 291 | + appendLine("## Budget") |
| 292 | + appendLine("- ResourceAllocation: ${Budget.ResourceAllocation.description}") |
| 293 | + appendLine("- CostApproval: ${Budget.CostApproval.description}") |
| 294 | + appendLine("- Timeline: ${Budget.Timeline.description}") |
| 295 | + appendLine() |
| 296 | + |
| 297 | + appendLine("## Priorities") |
| 298 | + appendLine("- Conflict: ${Priorities.Conflict.description}") |
| 299 | + appendLine("- Reprioritization: ${Priorities.Reprioritization.description}") |
| 300 | + appendLine("- Dependency: ${Priorities.Dependency.description}") |
| 301 | + appendLine() |
| 302 | + |
| 303 | + appendLine("## Scope") |
| 304 | + appendLine("- Expansion: ${Scope.Expansion.description}") |
| 305 | + appendLine("- Reduction: ${Scope.Reduction.description}") |
| 306 | + appendLine("- Clarification: ${Scope.Clarification.description}") |
| 307 | + appendLine() |
| 308 | + |
| 309 | + appendLine("## External") |
| 310 | + appendLine("- Vendor: ${External.Vendor.description}") |
| 311 | + appendLine("- Customer: ${External.Customer.description}") |
| 312 | + } |
| 313 | + |
| 314 | + /** |
| 315 | + * Parses an escalation type from a string identifier. |
| 316 | + * Used to convert LLM output back to typed escalation. |
| 317 | + * |
| 318 | + * @param identifier The escalation type identifier (e.g., "Discussion.CodeReview") |
| 319 | + * @return The matching Escalation type, or null if not found. |
| 320 | + */ |
| 321 | + fun fromIdentifier(identifier: String): Escalation? { |
| 322 | + val normalized = identifier.trim() |
| 323 | + return when { |
| 324 | + // Discussion |
| 325 | + normalized.contains("CodeReview", ignoreCase = true) -> Discussion.CodeReview |
| 326 | + normalized.contains("Design", ignoreCase = true) && |
| 327 | + !normalized.contains("Redesign", ignoreCase = true) -> Discussion.Design |
| 328 | + normalized.contains("Architecture", ignoreCase = true) -> Discussion.Architecture |
| 329 | + normalized.contains("Requirements", ignoreCase = true) -> Discussion.Requirements |
| 330 | + |
| 331 | + // Decision |
| 332 | + normalized.contains("Technical", ignoreCase = true) -> Decision.Technical |
| 333 | + normalized.contains("Product", ignoreCase = true) -> Decision.Product |
| 334 | + normalized.contains("Authorization", ignoreCase = true) -> Decision.Authorization |
| 335 | + |
| 336 | + // Budget |
| 337 | + normalized.contains("ResourceAllocation", ignoreCase = true) -> Budget.ResourceAllocation |
| 338 | + normalized.contains("CostApproval", ignoreCase = true) -> Budget.CostApproval |
| 339 | + normalized.contains("Timeline", ignoreCase = true) -> Budget.Timeline |
| 340 | + |
| 341 | + // Priorities |
| 342 | + normalized.contains("Conflict", ignoreCase = true) -> Priorities.Conflict |
| 343 | + normalized.contains("Reprioritization", ignoreCase = true) -> Priorities.Reprioritization |
| 344 | + normalized.contains("Dependency", ignoreCase = true) -> Priorities.Dependency |
| 345 | + |
| 346 | + // Scope |
| 347 | + normalized.contains("Expansion", ignoreCase = true) -> Scope.Expansion |
| 348 | + normalized.contains("Reduction", ignoreCase = true) -> Scope.Reduction |
| 349 | + normalized.contains("Clarification", ignoreCase = true) -> Scope.Clarification |
| 350 | + |
| 351 | + // External |
| 352 | + normalized.contains("Vendor", ignoreCase = true) -> External.Vendor |
| 353 | + normalized.contains("Customer", ignoreCase = true) -> External.Customer |
| 354 | + |
| 355 | + else -> null |
| 356 | + } |
| 357 | + } |
| 358 | + } |
| 359 | +} |
0 commit comments