Expand description
Ingest selection + backoff — pick the next due (binding, operation)
pair in a --all rotation, skipping pairs whose destination is unchanged
and whose sources have not moved. Engine-side generalization of the
plugin’s nextIngest / shouldSkip / backoff state from “next due binding
(build)” to a per-operation rotation.
Eligibility (per pair): an operation participates in the rotation only
when its operations.<op> block exists in the binding and declares
trigger: loop — consent to unattended rotation lives in the declaration.
A one-shot build that already ran stays excluded.
Due-checks (cheap, per pair, before backoff): build is always due
(unchanged semantics — backoff alone decides); sync is due when a source
moved past its #synced baseline or open findings exist under the
binding’s current (hash(D), source_head) key; verify is due when a source
moved past its #verified baseline (a never-verified source with a live
token counts as moved — the first verify is due). A pair that is not due is
passed over without touching its backoff state.
The deterministic state (round-robin cursor, per-pair backoff, one-shot
ran-set) lives engine-side under <workspace>/.memstead.cache/ingest/ —
the same engine-internal bookkeeping location the mtime memo uses. This is
not mem-repo / graph state; selection mutates it as its job. Cursor and
backoff entries are keyed by the pair id <binding>#<op>; pre-pair
single-key entries (plain binding ids) are discarded — the cache is
disposable, and the cost is at most one lost backoff step per binding.
Backoff shape (mirrors the plugin exactly): a linear-ramp per-pair
skip counter. A destination-snapshot change or a moved source resets it
to zero and runs; otherwise each unproductive pass grows the cooldown by
one (capped at MAX_SKIP_LEVEL). A one-shot build never skips. For sync
/ verify pairs the moved-source override is not applied: the due-check
already encodes source movement, and a productive run mutates the
destination mem, which resets the pair’s backoff by itself — so an
un-acted-on brief ramps instead of being re-rendered every pass.
Structs§
- Backoff
Entry - Per-ingest destination-snapshot backoff state.
- Cursor
- The round-robin cursor — the (binding, operation) pair the last rotation
advanced to, stored as the pair id
<binding>#<op>. A pre-pair value (a plain binding id) never matches a pair id, so the first op-aware pass simply restarts the rotation from the top — the cache is disposable.
Enums§
- Operation
Filter - Which operations a
--allrotation considers.Only(op)restricts the eligible set to that operation’s pairs (the CLI default isOnly(Build)— byte-stable for the ingest router);Self::Anyrotates across every eligible pair. - Operation
Kind - One operation of a binding — the second half of a
--allrotation pair.
Constants§
- MAX_
SKIP_ LEVEL - The backoff cooldown ceiling — after this many consecutive unproductive
passes the skip count stops growing. Mirrors the plugin’s
MAX_SKIP_LEVEL.
Functions§
- apply_
backoff - Apply the destination-snapshot backoff to
entry, mutating it, and return whether to skip this pass.currentis the destination mem’s current snapshot token (empty when none). Mirrors the backoff block of the plugin’sshouldSkip: - select_
next_ due - Select the next due ingest (build operation) for a
--allrotation — the build-only compatibility form ofselect_next_due_operation. Returns the selected binding id, orNonewhen nothing is due this pass. - select_
next_ due_ operation - Select the next due (binding, operation) pair for a
--allrotation, advancing the round-robin cursor and the per-pair backoff state. Returns the selected binding id and operation, orNonewhen nothing eligible is due (or everything due is backing off) this pass. - should_
skip - Whether a binding should be skipped this rotation. A one-shot build never
skips (one-shots are excluded from the eligible set once run). Discovery: a
moved source overrides backoff; otherwise the destination-snapshot
apply_backoff.