symfonic.capabilities.memory.cadence¶
cadence ¶
When a scope is next due, counted per scope and decided without awaiting.
Split from :mod:symfonic.capabilities.memory.napping at the 300-line budget,
and the two halves are two questions: this one answers whether a scope
consolidates, and the module it left owns the work once it does.
Worth its own module for a second reason. The shipped engine counted turns on the agent, so two tenants served by one process shared a cadence and either consolidated on the other's turns. The counter being keyed by scope is the fix, and keeping it in one small object is what makes that visible.
Cadence ¶
Cadence(schedule: ConsolidationSchedule, cycles: Sequence[ConsolidationCycle], cursors: MutableMapping[str, ScheduleCursor] | None = None)
One counter per scope, and the rule that reads it.
Source code in src/symfonic/capabilities/memory/cadence.py
after_turn ¶
Record a successful turn and answer which cycle is now due.
No await anywhere in this method, deliberately: the read, the
arithmetic and the write are one step, so two turns completing at once
cannot both be told the same turn count is due.
Source code in src/symfonic/capabilities/memory/cadence.py
cursor ¶
This scope's counter. A scope nobody has served yet has a fresh one.
uncomplete ¶
Put the cursor back on the threshold after a cancelled cycle.
after_turn reset it to zero on the way in, so leaving it there
would cost this scope a whole cadence for a cycle that never ran. Back
to the threshold, not back by one: the turns that earned this nap
already happened.