SRD 'Full-Round Actions - Restricted Withdraw': 'If you are limited to taking only a standard action each round you can withdraw as a standard action. In this case, you may move up to your speed.' _staggered_filter now keeps withdraw as the one move-or-standard action (spending the slot) instead of dropping it, and _flee_path halves the budget to single speed for a staggered/disabled creature (new _is_staggered_limited helper). Filter-level and engine-level tests added.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
PF1e (CRB, Staggered): a staggered creature takes a single move OR standard action but can still take free, swift, and immediate actions. _staggered_filter returned only the first non-full-round action, so a disabled combatant with a queued swift bonus (deed/inspire_courage) lost its standard action. It now keeps every swift and free action plus the first move-or-standard, preserving the full_attack -> single attack downgrade.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
SpellSpec gains a cast_time field (seven budget codes; the JSON loader
also accepts RAW phrasings like "1 round" or "1 minute"). The pure
budget filters take a CastTimeResolver so a cast_spell occupies the slot
its casting time maps to: standard->standard, swift->swift (competing
with deed/inspire courage and dropped by a consumed immediate),
immediate/free->free, full_round and one_round->full_round (one_round
clamped: resolved end-of-turn, documented approximation), long->dropped
before the budget filter with the new downgraded:cast_time reason. The
engine binds its registry lookup via _cast_time_of (unknown names fall
back to standard, keeping transcripts byte-identical);
_choose_spell_action never selects long casts; the staggered filter now
drops full-round casts and spell_combat via the effective slot
(_FULL_ROUND_KINDS becomes dead and is deleted). Summon Monster I/II are
the only data spells marked 1 round. Metamagic full-round casting for
spontaneous casters is out of scope (future hook documented in
_cast_time_of).
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
PF1e CRB (Actions in Combat): a move action can be taken instead of the
standard one. The budget filter now converts a second move action onto
the standard slot when the move slot is spent and the standard is still
free, so (move, stand_up) and (move, move) are legal; a third move (or
any further standard) is still surplus. The greedy walk is expressed
with a spent-slot map to stay inside the C901 complexity ceiling.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
PF1e CRB: running is a full-round action, not a move action. The budget
filter now classifies run as full-round (consumes the standard AND the
move slot), _FULL_ROUND_KINDS includes it for the staggered filter, and
the nauseated filter drops it (run is no longer move-like). The
moved_this_turn/running flags are unchanged; the _execute_run
moved_this_turn early return stays as defense in depth. default_policy
never emits run, so the golden transcripts are untouched.
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Apply the PF1e per-turn action budget (CRB Actions in Combat: one
standard + one move, or one full-round in place of both, plus one
swift) unconditionally to every sequence a policy returns, not only
the immediate/staggered/nauseated specializations.
- _action_economy_filter: greedy in-order walk keeping the earliest
legal prefix-subsequence; a full-round action is only kept while
both the standard and move slots are still free.
- Exhaustive kind->slot classification (standard / move / swift /
full_round / free-conditional) over the Action.kind Literal,
documented and locked by tests.
- Surplus actions dropped and reported as
ActionResult(ok=False, reason="downgraded:action_economy") via a
multiset drop diff (reports duplicate-kind surplus the set-based
_dropped_kinds cannot).
- Composition order: general budget first, then the existing
immediate/staggered/nauseated filters (unchanged).
- default_policy untouched and its turns verified legal by the
validator; golden transcripts byte-identical.