"""Integration: the owner's org policy is honoured by the real scheduler tick. The tick reads the policy through the manager's grants port, once per organization, and checks two of its switches before a turn is spent: * ``automation_enabled`` off stops every turn and every merge. The stage does not move, so switching automation back on resumes the task where it was (the owner's human-off switch). * ``monthly_credit_budget`` is a ceiling on the organization's spend since the first day of the UTC month. Spend at or above it pauses the task. With no policy (the default), the tick behaves as the flow tests pin it. The fixtures and the scheduler wiring come from ``tests.test_engine_flow``; this module adds the owner's policy and the spend guard on top of them. """ from __future__ import annotations from app.application.engine.scheduler import Scheduler from app.application.ports.delivery_hooks import NullDeliveryHooks from app.application.ports.model_grants import DefaultOrgPolicy, OrgPolicyView from app.application.ports.repo_workspace import FakeRepoWorkspace from app.domain.workforce.pipeline import Stage from app.infrastructure.db.models import UsageEventRow from app.infrastructure.repositories.engine import PipelineStateRepository, TaskSpendRepository from tests.engine_fakes import ( FakeGrants, FakeSandbox, RecordingMemory, ScriptedModel, ScriptedReply, ) from tests.test_engine_flow import _run, _scheduler, _task, _team from tests.test_engine_flow import world as flow_world #: The flow tests' organization fixture. Binding it under its own name registers it #: for this module's tests (a bare import would be flagged as unused and shadowed). world = flow_world async def _wired( session, world, *, scripted: ScriptedModel, policy: OrgPolicyView | None ) -> Scheduler: """The flow test's scheduler, with the owner's policy and the spend guard wired in.""" scheduler = _scheduler( session, world, scripted=scripted, sandbox=FakeSandbox(), workspace=FakeRepoWorkspace(), memory=RecordingMemory(), delivery=NullDeliveryHooks(), ) # The tick reads the owner's policy through the manager's grants port. scheduler.manager.grants = FakeGrants({world.strong_id: "strong"}, policy=policy) scheduler.spend = TaskSpendRepository(session) return scheduler def _usage(world, total_price: float) -> UsageEventRow: """A ledger row for this organization, stamped now (so it falls in this month).""" return UsageEventRow( organization_id=world.organization_id, unit="model_input_tokens", quantity=1000.0, unit_price=0.0000004, total_price=total_price, ) async def test_automation_off_stops_the_turn_and_moves_no_stage(world, session_factory): """The owner's human-off switch: no turn is spent and the task keeps its stage.""" scripted = ScriptedModel([ScriptedReply(content="[[ASSIGN/]]")]) async with session_factory() as session: await _team(session, world) row = await _task(session, world, stage=Stage.PENDING_MANAGER_REVIEW) await session.commit() scheduler = await _wired( session, world, scripted=scripted, policy=DefaultOrgPolicy(automation_enabled=False) ) report = await scheduler.tick() state = await PipelineStateRepository(session).get(row.id) assert state is not None and state.stage is Stage.PENDING_MANAGER_REVIEW assert report.skipped == 1 assert scripted.calls == 0 async def test_a_spent_monthly_budget_pauses_before_a_turn_is_spent(world, session_factory): """A budget of 0.0 with any spend this month is used up, so the task pauses.""" scripted = ScriptedModel([ScriptedReply(content="[[ASSIGN/]]")]) async with session_factory() as session: await _team(session, world) row = await _task(session, world, stage=Stage.PENDING_MANAGER_REVIEW) session.add(_usage(world, total_price=0.25)) await session.commit() scheduler = await _wired( session, world, scripted=scripted, policy=DefaultOrgPolicy(monthly_credit_budget=0.0) ) await _run(scheduler, session, 1) state = await PipelineStateRepository(session).get(row.id) assert state is not None and state.stage is Stage.PAUSED assert scripted.calls == 0 async def test_spend_under_the_monthly_budget_does_not_pause(world, session_factory): """Spend below the monthly budget leaves the task free to take its turn.""" scripted = ScriptedModel([ScriptedReply(content="[[ASSIGN/]]")]) async with session_factory() as session: await _team(session, world) row = await _task(session, world, stage=Stage.PENDING_MANAGER_REVIEW) session.add(_usage(world, total_price=0.25)) await session.commit() scheduler = await _wired( session, world, scripted=scripted, policy=DefaultOrgPolicy(monthly_credit_budget=10.0) ) await _run(scheduler, session, 1) state = await PipelineStateRepository(session).get(row.id) assert state is not None and state.stage is not Stage.PAUSED assert scripted.calls == 1 async def test_no_policy_keeps_the_default_behaviour(world, session_factory): """With no owner policy the default applies: automation on, no monthly budget.""" scripted = ScriptedModel([ScriptedReply(content="[[ASSIGN/]]")]) async with session_factory() as session: await _team(session, world) row = await _task(session, world, stage=Stage.PENDING_MANAGER_REVIEW) await session.commit() scheduler = await _wired(session, world, scripted=scripted, policy=None) await _run(scheduler, session, 1) state = await PipelineStateRepository(session).get(row.id) assert state is not None and state.stage is not Stage.PAUSED assert scripted.calls == 1