T-EJ3P-gs-stateful-tracker
Status: planning/backlog · Impact: low · Complexity: small
Add the stateful convenience wrapper graph_scheduler::tracker, behind an
optional tracker Cargo feature.
Deferred until after cutover. Not part of graph-scheduler v0.1. The engine
holds its own state on the lease and the run journal and re-reads it each tick,
so it calls the pure get_ready directly and has no use for a wrapper that owns
state. This task is parked at planning/backlog and is re-promoted when a
consumer that wants the convenience actually exists — which is the
P-0012-rust-core-adapters-as-needed test, applied to a layer rather than a
language.
Impact is lowered to low for the same reason: StatusSource, landed by
T-CLV1-gs-status-model-and-trigger-rules, already removes most of the
plumbing this wrapper was meant to remove.
| Location | Role today |
|---|---|
packages/rust/graph-scheduler/src/tracker.rs | Does not exist. Not scaffolded by T-ROJC-gs-test-corpus-and-disabled-suites |
packages/rust/graph-scheduler/src/status.rs | StatusSource already covers the “derive state from the caller’s store” half of this capability |
packages/rust/intersect/Cargo.toml | The precedent for a layer behind an optional Cargo feature — its fs feature mirrors a TypeScript subpath export |
Proposed
Section titled “Proposed”src/tracker.rs, gated by an optional tracker feature.
| Item | Shape |
|---|---|
Tracker::new(Graph) | Owns an internal BTreeMap<NodeId, NodeStatus>, all Pending |
Tracker::with_status(Graph, impl StatusSource) | Reads state from the caller’s source instead |
ready(&ReadyOptions) -> Vec<ReadyNode> | Same frontier as get_ready on equivalent state |
start(&NodeId) | Sets Running |
complete(&NodeId, NodeStatus) | Defaults to Success, re-opening the frontier |
explain(&NodeId) -> Explanation | Delegates to Schedule::explain |
D-BPD8 lists the tracker as the graph-scheduler/tracker subpath. Rust has no
export map, so the closest idiom for an opt-in layer is a Cargo feature —
exactly how packages/rust/intersect expresses its fs entry point. Default-off
here, since the engine does not want it.
The wrapper adds no behaviour. It must return the same frontier the pure engine returns for equivalent state, and the parity fixture is what proves it.
Approach
Section titled “Approach”- Add the optional
trackerfeature and implementsrc/tracker.rsoverScheduleandget_ready. - Land the Layer 8 fixture table from T-ROJC’s matrix as a
consttable intests/tracker.rs, un-ignored, and make it green. - Extend
moon.yml’stesttask to--all-featuresso the gated layer is covered in CI, matching intersect.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
packages/rust/graph-scheduler/src/tracker.rs | new | Tracker over the pure engine |
packages/rust/graph-scheduler/Cargo.toml | modify | Add the optional tracker feature |
packages/rust/graph-scheduler/src/lib.rs | modify | Feature-gated module declaration and re-export |
packages/rust/graph-scheduler/moon.yml | modify | Run test with --all-features |
packages/rust/graph-scheduler/tests/tracker.rs | new | Layer 8 fixtures, including the parity case |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
Trackersupportsready,start,completeandexplain, over either an internal map or a suppliedStatusSource. - AC-2:
startexcludes a node from the next frontier;completewith the default outcome re-opens its dependents. - AC-3: Tracker results equal
get_readyon equivalent state at every step, asserted by the parity fixture rather than by inspection. - AC-4: The layer is behind a default-off
trackerfeature, andcargo build -p graph-schedulerwithout features compiles nothing fromtracker.rs. - AC-5: Every row of T-ROJC’s Layer 8 fixture table passes under
--all-features.
Out of scope
Section titled “Out of scope”- Any change to the pure engine. If the tracker needs one, that is a defect in the engine’s surface, not tracker work.
- Pull resolution (T-0WNK-gs-pull-resolution).
Dependencies
Section titled “Dependencies”- T-8L0G-gs-goal-directed-frontier — the tracker wraps the engine through the goal-directed
layer, so
readyacceptstowardlike any other caller.
Depends on
Section titled “Depends on”T-8L0G-gs-goal-directed-frontier