T-I3QP-gs-push-readiness-frontier
Status: open/ready · Impact: high · Complexity: medium
Implement the push readiness engine as graph_scheduler::ready: get_ready is
a pure function of graph and state returning the nodes runnable now. This is the
load-bearing surface the E6 dispatcher tick calls in-process. On the v0.1
critical path.
| Location | Role today |
|---|---|
packages/rust/graph-scheduler/src/ready.rs | Stubbed by T-ROJC-gs-test-corpus-and-disabled-suites; get_ready is a todo!() |
packages/rust/graph-scheduler/src/graph.rs | The DAG core, landed by T-JVXC-gs-dag-core |
packages/rust/graph-scheduler/src/status.rs | NodeStatus, TriggerRule, StatusSource, landed by T-CLV1-gs-status-model-and-trigger-rules |
solutions/ontological/lib/model/entities/task/ops/next.ts | sdlc task next’s hand-written frontier — build edges, drop unsatisfied depends_on, sort, cap. Stays as-is; C4 rebases it later |
Proposed
Section titled “Proposed”src/ready.rs holds the frontier query.
| Item | Shape |
|---|---|
ReadyNode | id: NodeId, attrs: NodeAttrs |
ReadyOptions | limit: Option<usize>, where_fn: Option<Box<dyn Fn(&ReadyNode) -> bool>>, order: Option<Box<dyn Sorter>>, toward: Vec<NodeId> |
get_ready(&Graph, &impl StatusSource, &ReadyOptions) -> Vec<ReadyNode> | The frontier |
A node is in the frontier exactly when its own status is Pending and its
TriggerRule is satisfied by its parents’ statuses. Dependency satisfaction is
not a separate check — it is the default AllSuccess rule. Running nodes are
never returned, which is what makes a re-read-each-tick dispatcher unable to
double-dispatch.
ReadyOptions declares order and toward from the start so later tasks fill
them in rather than widening the struct. toward stays unread until
T-8L0G-gs-goal-directed-frontier; order until
T-BR6H-gs-priority-sorters. The struct is #[non_exhaustive] with a
Default and builder setters, so adding a field later is not a breaking
change. The setters are what make that true: a #[non_exhaustive] struct
admits no struct expression outside its defining crate — functional update
included — so ..Default::default() does not compile for a caller, and the
integration suites are callers.
Determinism: with no sorter, the frontier comes back in add_node insertion
order (T-ROJC ratified default R-1). A cyclic graph yields an empty frontier
rather than an error — no node on a cycle can satisfy its rule.
Approach
Section titled “Approach”- Implement
get_readyover the DAG core andStatusSource: collectPendingnodes, test each node’s trigger rule against its parents’ statuses, applywhere_fn, then truncate tolimit. - Keep it a pure function — no interior mutability, no caching, nothing that makes two calls with the same arguments disagree.
- Un-ignore the Layer 3 suite in
tests/ready.rsand make it green.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
packages/rust/graph-scheduler/src/ready.rs | modify | Replace stubs with the frontier engine |
packages/rust/graph-scheduler/src/lib.rs | modify | Re-export get_ready, ReadyNode, ReadyOptions |
packages/rust/graph-scheduler/tests/ready.rs | modify | Remove #[ignore] from the Layer 3 suite |
packages/rust/graph-scheduler/tests/graph.rs | modify | Remove the #[ignore] on f_cycle_get_ready — a Layer 1 fixture that exercises get_ready, left tagged to this task by T-JVXC-gs-dag-core |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
get_readyreturnsPending, trigger-satisfied nodes only, truncated tolimitwhen set. - AC-2:
Runningnodes never appear in the frontier. - AC-3: A node whose
depends_ontarget is absent from the graph stays out of the frontier under the default rule (first-consumer requirement C, fail-safe). - AC-4:
get_readyis pure — two calls with the same graph and state return the same ordering, asserted by a test. - AC-5: A cyclic graph returns an empty frontier and no error.
- AC-6: Every row of T-ROJC’s Layer 3 fixture table passes and the suite in
tests/ready.rshas no#[ignore]left.
Out of scope
Section titled “Out of scope”- Registered filters and
explain(T-7OJL-gs-eligibility-filters-and-explain). - Sorters (T-BR6H-gs-priority-sorters) and goal-direction
(T-8L0G-gs-goal-directed-frontier) — their
ReadyOptionsfields are declared here but unread. - Rebasing
sdlc task nextonto this frontier. That is Track C (C4).
Dependencies
Section titled “Dependencies”- T-CLV1-gs-status-model-and-trigger-rules — the frontier consumes
NodeStatus,TriggerRule::is_satisfied_byandStatusSource.
Depends on
Section titled “Depends on”T-CLV1-gs-status-model-and-trigger-rules