|null $limit_rule The rule whose rate limit * denied, for the anomaly alert the * caller raises once the denial is * recorded (ADR-17). * @param bool $unresolved Whether the deciding rule fired on a * condition that could not be * evaluated (ADR-18 §4). * @param bool $over_budget Whether the deciding rule fired * because the action would exceed its * budget (ADR-18 §6). * @param string|null $extension The extension whose default rule * decided (AF-25.10). The policy id is * then null and the rule index is the * rule's among that extension's defaults. * @param bool $admin_guard Whether the guard on administrator-run * agents raised the decision (AF-25.15). */ public function __construct( public readonly Decision $decision, public readonly ?string $reason = null, public readonly ?int $policy_id = null, public readonly ?int $rule_index = null, public readonly ?int $retry_after = null, public readonly bool $ai_triage = false, public readonly bool $network = false, public readonly ?array $limit_rule = null, public readonly bool $unresolved = false, public readonly bool $over_budget = false, public readonly ?string $extension = null, public readonly bool $admin_guard = false ) { } /** * Whether a stored rule decided, rather than the built-in defaults. */ public function matched_a_rule(): bool { return null !== $this->policy_id; } /** * Whether waiting and retrying could succeed. */ public function is_retryable(): bool { if ( self::REASON_BUDGET === $this->reason ) { return null !== $this->retry_after; } return self::REASON_RATE_LIMITED === $this->reason || self::REASON_LEDGER_BUSY === $this->reason; } }