Weighted thresholds
ApprovalRule::Weighted (and Quorum) resolve on the summed weight of approvals rather than a head-count; the quorum value is the weight threshold. Plain quorum keeps working unchanged because every decision defaults to weight 1.
Weight per actor
Implement ProvidesApprovalWeight on the actor model. approvalWeight() receives the approvable, so a weight can depend on what is being decided:
use Illuminate\Database\Eloquent\Model;
use RoundlyConsulting\Approvals\Interfaces\ProvidesApprovalWeight;
use RoundlyConsulting\Approvals\Traits\GivesApprovals;
class User extends Model implements ProvidesApprovalWeight
{
use GivesApprovals;
public function approvalWeight(?Model $approvable = null): int
{
return $this->is_director ? 3 : 1;
}
}use RoundlyConsulting\Approvals\Facades\Approvals;
Approvals::request($release)->from([$director, $analyst])->weighted(3)->open();
Approvals::for($release)->as($analyst)->approve(); // weight 1 — still pending: the director's 3 can still reach it
Approvals::for($release)->as($director)->approve(); // weight 3 meets the threshold -> approvedWhen a threshold request rejects
A threshold request rejects once the threshold is out of reach: the approval weight in, plus the weight the undecided named approvers carried when the request opened, falls short of it. A light approver deciding first therefore never rejects a request a heavier one can still carry.
- Without named approvers, each outstanding slot counts as weight 1 under Quorum.
- An unnamed Weighted request can’t know what its approvers weigh, so it only rejects once every slot has decided.
- Unanimous and Any count heads, not weights.
Weight per decision
Override the weight of a single decision with weight() on the builder — the action equivalent is DecisionData::approved(weight: …):
use RoundlyConsulting\Approvals\Facades\Approvals;
// This one approval counts double, whatever approvalWeight() returns.
Approvals::for($release)->as($analyst)->weight(2)->approve();Overrides are not anticipated when checking reachability — give approvers their weight through ProvidesApprovalWeight when a request depends on it.
Resolution order
- An explicit per-decision override — clamped to 0 or more.
- The actor’s approvalWeight() when it implements ProvidesApprovalWeight — also clamped to 0 or more.
- Otherwise the default weight of 1.
The resolved weight is stored on the decision’s weight column, so tallies never re-ask the actor. For a delegated decision the weight is resolved from the delegator — the model whose authority it counts as. ApprovalRule::isWeighted() returns true for both Weighted and Quorum, which share the threshold path.
The RequiresApproval shorthand takes the rule as an argument: $release->requestApproval([$director, $analyst], ApprovalRule::Weighted, quorum: 3).
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.