(actor ActorContext, taskID string)
| 430 | } |
| 431 | |
| 432 | func (m *Service) requireForceRunRate(actor ActorContext, taskID string) error { |
| 433 | if actor.Actor.Kind.Normalize() != ActorKindAgentSession { |
| 434 | return nil |
| 435 | } |
| 436 | now := m.now().UTC() |
| 437 | if m.forceRateLimiter.allow(actor.Actor, taskID, now, m.forceRecovery.RateLimitPerMinute) { |
| 438 | return nil |
| 439 | } |
| 440 | return forceRunDiagnosticError( |
| 441 | diagnosticcontract.CodeForceOpRateLimited, |
| 442 | "Force operation rate limit exceeded", |
| 443 | fmt.Sprintf( |
| 444 | "Actor %s exceeded %d force operations per minute for task %s.", |
| 445 | actor.Actor.Ref, |
| 446 | m.forceRecovery.RateLimitPerMinute, |
| 447 | taskID, |
| 448 | ), |
| 449 | diagnosticcontract.SeverityWarn, |
| 450 | "agh task inspect "+taskID, |
| 451 | map[string]any{ |
| 452 | "actor_kind": string(actor.Actor.Kind.Normalize()), |
| 453 | "actor_id": actor.Actor.Ref, |
| 454 | taskEvidenceIDKey: taskID, |
| 455 | "limit": m.forceRecovery.RateLimitPerMinute, |
| 456 | }, |
| 457 | ErrForceOpRateLimited, |
| 458 | ) |
| 459 | } |
| 460 | |
| 461 | func (m *Service) invalidateForceRunInputs(ctx context.Context, previous Run) (int64, int, error) { |
| 462 | sessionID := strings.TrimSpace(previous.SessionID) |
no test coverage detected