T-0WNK-gs-pull-resolution
Status: planning/backlog · Impact: low · Complexity: small
Add the demand-driven variant graph_scheduler::pull: resolve(graph, state, goal, limit) — runnable work toward a goal, resolved over the goal’s ancestors
instead of enumerating the global frontier. Behind an optional pull Cargo
feature.
Deferred until after cutover. Not part of graph-scheduler v0.1. D-BPD8’s own
open question asks whether to ship pull at all or defer to goal-directed push
alone, and it is still open. The engine’s dispatcher tick is level-triggered — it
recomputes the whole frontier every tick — which is the push model, so nothing in
v0.1 has a reason to pull. Parked at planning/backlog.
need_human_review is set because this task may not survive: if
T-8L0G-gs-goal-directed-frontier lands and no consumer asks for lazy
resolution, the right outcome is closing this as superseded rather than building
a second path to the same answer.
| Location | Role today |
|---|---|
packages/rust/graph-scheduler/src/pull.rs | Does not exist. Not scaffolded by T-ROJC-gs-test-corpus-and-disabled-suites |
packages/rust/graph-scheduler/src/goal.rs | only_toward gives the same answer set eagerly; pull’s only claim is avoiding the global frontier |
docs/planning/decisions/D-BPD8-graph-scheduler-api/README.md | Open question: ship pull in v1, or defer to goal-directed push only |
Proposed
Section titled “Proposed”src/pull.rs, gated by an optional pull feature, mirroring the tracker’s
treatment of a D-BPD8 subpath as a Cargo feature.
| Item | Shape |
|---|---|
resolve(&Graph, &impl StatusSource, &NodeId, Option<usize>) -> Vec<ReadyNode> | Runnable nodes toward the goal |
The traversal walks the goal’s unfinished ancestors on demand and stops at
satisfied prerequisites, rather than computing the global frontier and
intersecting. The result must equal get_ready with where_fn: only_toward(goal) — the fixture asserts that equality, so the two paths cannot
diverge in behaviour while differing in cost.
That equality is also the test of whether this task should exist. If the lazy walk is not measurably cheaper on a graph large enough to matter, it is a second implementation of an answer the crate already has.
Approach
Section titled “Approach”- Add the optional
pullfeature and implementresolveas a lazy walk overGraph::ancestors, reusing the frontier predicate rather than restating it. - Land the Layer 7 fixture table from T-ROJC’s matrix as a
consttable intests/pull.rs, un-ignored, including the equality case againstonly_toward. - Record a measurement against the eager path in the PR body, so the D-BPD8 open question is closed with evidence either way.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
packages/rust/graph-scheduler/src/pull.rs | new | Demand-driven resolve |
packages/rust/graph-scheduler/Cargo.toml | modify | Add the optional pull feature |
packages/rust/graph-scheduler/src/lib.rs | modify | Feature-gated module declaration and re-export |
packages/rust/graph-scheduler/tests/pull.rs | new | Layer 7 fixtures |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
resolve(graph, state, goal, limit)returns the runnable nodes toward the goal, honouringlimit. - AC-2: The traversal is lazy — it does not enumerate nodes outside the goal’s ancestor set, asserted by instrumenting node visits rather than by inspection.
- AC-3:
resolvereturns the same id set asget_readywithwhere_fn: only_toward(goal). - AC-4: The layer is behind a default-off
pullfeature. - AC-5: Every row of T-ROJC’s Layer 7 fixture table passes under
--all-features. - AC-6: The PR records the cost comparison against the eager path, closing D-BPD8’s open question with a measurement.
Out of scope
Section titled “Out of scope”- The stateful tracker (T-EJ3P-gs-stateful-tracker).
- Any change to the push frontier. Pull reuses its predicate and does not fork it.
Dependencies
Section titled “Dependencies”- T-8L0G-gs-goal-directed-frontier — pull reuses
only_towardas its correctness reference and overlaps goal-directed push by design.
Depends on
Section titled “Depends on”T-8L0G-gs-goal-directed-frontier