sts2-bot/docs/POLICY.md

3 KiB

Policy structure

Current boundaries

run.py                 observe, execute, report results, record the session
brain.py               entry point, dispatch, navigation, shops, minigames
policy/
    __init__.py        package marker; no registration or initialization
    context.py         Decision, PendingAction, PolicyContext
    combat.py          combat proposals and model questions
    selection.py       card, relic, bundle, hand, and reward proposals
facts.py               observation parsing and combat calculations

brain.decide() remains the policy entry point. The runner owns one PolicyContext per session and reports action results to it. brain.Decision and brain.PolicyContext remain available as direct imports of the shared types, so the runner interface does not change.

Policy modules may ask Jev for preferences. They must not call the game API. context.py does not call either service. Combat arithmetic remains in facts.py, not duplicated inside combat policy.

The dependency direction is simple:

  • The runner uses brain.
  • brain uses the combat, selection, and context modules.
  • Combat and selection use context, facts, and the model client.
  • Context uses only the Python standard library.
  • No policy module imports brain or the runner.

State and configuration

A proposal does not update execution memory. Accepted requests are reconciled with fresh observations. See policy-state behavior and limits for the evidence required by each guarded action.

The existing card-skip setting stays in brain.CARD_SKIP_POLICY. The dispatcher passes its value explicitly to selection.card_reward_decision(skip_policy=...). This avoids a circular import and preserves the existing command-line behavior. It is configuration, not per-screen action memory.

Why stop here

These are plain modules, not a plugin framework or class hierarchy. Navigation, shops, and minigames stay together until a further split helps development.

The extraction does not change game decisions, confidence gates, fallbacks, state reconciliation, or recording. Run identity and persistent-deck provenance remain separate work.

Extraction verification

  • 262 existing assertions passed. No test files or assertions were added for the extraction.
  • Thirteen isolated whole-process scenarios passed with local HTTP fixtures.
  • All 346 stored observations produced identical decisions before and after extraction, in both model-free mode and local-model-stub mode: 692 comparisons.
  • The local model requests also matched, including their state and questions.
  • Thirty-six function/class definitions retained identical abstract syntax trees. Only the two dispatch functions and explicit card-skip parameter changed.
  • Dataset integrity, Python compilation, and shell syntax checks passed.

The differential and whole-process probes were temporary. They made no live game or paid model calls. These checks establish refactoring equivalence for the tested inputs, not correctness for every possible game state.