Skip to content

Eligibility filters

Status: open/planned · Kind: component · Audience: user

  • Registered filters that gate which ready nodes are returnable, each returning a reasoned verdict (eligible / ineligible-with-reason), not a bare bool.
  • A two-tier rejection (retry-on-change vs never) powers explain() and tells the caller whether to re-test the node next tick.
  • Sub-capability of C-D2GO-readiness-scheduling.

A filter is a named predicate over a node (the Kubernetes Filter model). It receives the node and a context — the batch so far, in-flight counts, a handle to the caller’s store — and returns Verdict::Ok or Verdict::Blocked. Filters are hard gates: a node the frontier would return is withheld if any applicable filter blocks it. Because the verdict carries a reason, explain can say why a node is not runnable. A per-category in-flight cap is just a filter that counts running-by-category.

Filters are expressed as a Filter trait rather than a bare closure, because a rule has to carry its own name — explain reports which rule blocked a node, and a closure has none. A named closure adapter covers the ergonomic case.

  • Schedule::filter(impl Filter) — named registration, with applies_to as the matcher-scoping hook.
  • filter_fn(name, predicate) and a variant taking an applies_to matcher — one Rust spelling for each TypeScript overload.
  • Verdicts: ctx.ok(), ctx.blocked(reason, Retry::OnChange | Retry::Never).
  • explain(state, id) — the blocking rules and reasons for a withheld node.
use graph_scheduler::{Retry, Schedule, filter_fn, filter_fn_scoped};
Schedule::new(&g)
.filter(filter_fn_scoped(
"no-lease",
|n| n.attrs.category.as_deref() == Some("impl"),
|node, ctx| match leases.is_held(&node.id) {
true => ctx.blocked("lease held", Retry::OnChange),
false => ctx.ok(),
},
))
.filter(filter_fn("cap-impl", |_node, ctx| {
match ctx.chosen_and_in_flight(|n| n.attrs.category.as_deref() == Some("impl")) >= 2 {
true => ctx.blocked("impl cap (2)", Retry::OnChange),
false => ctx.ok(),
}
}));
  • Registered Filter implementations, each with a name and an optional applies_to matcher.
  • Per query: the node and a FilterCtx (batch-so-far, in-flight counts, store handle).
  • A pass/withhold decision per node; explain reasons.
  • The primary extension surface. Callers register domain rules — leases, category caps, or scope-conflict via PR-0002-intersect.
  • This is the seam D-VSLI-distributed-work-runner-architecture’s six scheduling filters plug into. The filters themselves are engine policy and do not live in this domain-blind crate; only the contract does.
  • No code realizes this yet — the capability is planned. It lands with the crate at packages/rust/graph-scheduler/, filters and explain in src/schedule.rs. Until the crate exists there is no anchor to record here.
  • The two-tier retry hint mirrors Kubernetes Unschedulable vs UnschedulableAndUnresolvable; the reason stays with the verdict (avoiding Nomad’s metrics side-channel). Filter vs. sorter is the hard-vs-soft split (C-V44L-priority-ordering-sorters).
  • chosen_and_in_flight only means something given an evaluation order. Candidates are evaluated in final sort order, and “chosen” counts peers already selected this batch that passed every filter, plus nodes already Running. That is what lets a counting filter express an in-flight cap with no separate capacity primitive.

← Back to Capabilities