Feature: Per-Session and Per-Org Cost Budgets As a platform operator I want per-session and per-org cost budgets with hierarchy enforcement So that spending stays within defined limits at every tier # ---- SessionCostBudget model ---- Scenario: Create session cost budget with defaults When I create a session cost budget with defaults Then the session budget total_cost should be 0.0 And the session budget max_cost_usd should be None And the session budget utilization should be None And the session budget remaining should be None And the session budget is_exceeded should be false Scenario: Create session cost budget with cap When I create a session cost budget with max_cost_usd 100.0 Then the session budget total_cost should be 0.0 And the session budget max_cost_usd should be 100.0 Scenario: Session budget rejects negative max_cost When I try to create a session cost budget with max_cost_usd -1.0 Then a cost budget validation error should be raised Scenario: Session budget records cost Given a session cost budget with max_cost_usd 100.0 When I record session cost 25.0 Then the session budget total_cost should be 25.0 And the session budget utilization should be 0.25 And the session budget remaining should be 75.0 Scenario: Session budget rejects negative cost Given a session cost budget with max_cost_usd 100.0 When I try to record session cost -5.0 Then a cost budget validation error should be raised Scenario: Session budget rejects non-numeric cost Given a session cost budget with max_cost_usd 100.0 When I try to record session cost with type error Then a cost budget type error should be raised Scenario: Session budget is_exceeded when over cap Given a session cost budget with max_cost_usd 10.0 When I record session cost 15.0 Then the session budget is_exceeded should be true Scenario: Session budget would_exceed check Given a session cost budget with max_cost_usd 10.0 When I record session cost 8.0 Then the session budget would_exceed 5.0 should be true And the session budget would_exceed 1.0 should be false Scenario: Session budget would_exceed rejects negative Given a session cost budget with max_cost_usd 10.0 When I try to check would_exceed with -1.0 Then a cost budget validation error should be raised Scenario: Session budget would_exceed rejects non-numeric Given a session cost budget with max_cost_usd 10.0 When I try to check would_exceed with type error Then a cost budget type error should be raised # ---- OrgCostAccumulator model ---- Scenario: Create org accumulator with defaults When I create an org accumulator for org "org-1" Then the org accumulator total_cost should be 0.0 And the org accumulator max_cost_usd should be None Scenario: Create org accumulator with cap When I create an org accumulator for org "org-1" with max_cost_usd 500.0 Then the org accumulator max_cost_usd should be 500.0 Scenario: Org accumulator rejects negative max_cost When I try to create an org accumulator with max_cost_usd -10.0 Then a cost budget validation error should be raised Scenario: Org accumulator records cost Given an org accumulator for org "org-1" with max_cost_usd 500.0 When I record org cost 100.0 Then the org accumulator total_cost should be 100.0 And the org accumulator utilization should be 0.2 And the org accumulator remaining should be 400.0 Scenario: Org accumulator is_exceeded Given an org accumulator for org "org-1" with max_cost_usd 50.0 When I record org cost 60.0 Then the org accumulator is_exceeded should be true Scenario: Org accumulator rejects negative cost Given an org accumulator for org "org-1" with max_cost_usd 100.0 When I try to record org cost -5.0 Then a cost budget validation error should be raised Scenario: Org accumulator rejects non-numeric cost Given an org accumulator for org "org-1" with max_cost_usd 100.0 When I try to record org cost with type error Then a cost budget type error should be raised Scenario: Org accumulator would_exceed check Given an org accumulator for org "org-1" with max_cost_usd 50.0 When I record org cost 40.0 Then the org accumulator would_exceed 20.0 should be true And the org accumulator would_exceed 5.0 should be false # ---- ThreadSafeOrgCostAccumulator ---- Scenario: Thread-safe wrapper delegates correctly Given a thread-safe org accumulator for org "safe-org" with max_cost_usd 200.0 When I record thread-safe org cost 50.0 Then the thread-safe org total_cost should be 50.0 And the thread-safe org utilization should be 0.25 And the thread-safe org remaining should be 150.0 Scenario: Thread-safe wrapper snapshot Given a thread-safe org accumulator for org "snap-org" with max_cost_usd 100.0 When I record thread-safe org cost 30.0 And I take a snapshot of the thread-safe org accumulator Then the snapshot total_cost should be 30.0 And the snapshot org_id should be "snap-org" Scenario: Thread-safe wrapper rejects non-accumulator When I try to create a thread-safe wrapper with invalid argument Then a cost budget type error should be raised Scenario: Thread-safe wrapper is_exceeded Given a thread-safe org accumulator for org "ex-org" with max_cost_usd 10.0 When I record thread-safe org cost 15.0 Then the thread-safe org is_exceeded should be true Scenario: Thread-safe wrapper would_exceed Given a thread-safe org accumulator for org "we-org" with max_cost_usd 10.0 When I record thread-safe org cost 8.0 Then the thread-safe org would_exceed 5.0 should be true And the thread-safe org would_exceed 1.0 should be false Scenario: Thread-safe wrapper would_exceed rejects negative Given a thread-safe org accumulator for org "neg-org" with max_cost_usd 10.0 When I try to check thread-safe would_exceed with -1.0 Then a cost budget validation error should be raised Scenario: Thread-safe wrapper would_exceed rejects non-numeric Given a thread-safe org accumulator for org "te-org" with max_cost_usd 10.0 When I try to check thread-safe would_exceed with type error Then a cost budget type error should be raised Scenario: Thread-safe wrapper record_cost rejects negative Given a thread-safe org accumulator for org "rc-org" with max_cost_usd 10.0 When I try to record thread-safe org cost -3.0 Then a cost budget validation error should be raised Scenario: Thread-safe wrapper record_cost rejects non-numeric Given a thread-safe org accumulator for org "rcte-org" with max_cost_usd 10.0 When I try to record thread-safe org cost with type error Then a cost budget type error should be raised # ---- CostBudgetService ---- Scenario: Service configure session budget Given a cost budget service When I configure session "sess-1" with max_cost_usd 50.0 Then session "sess-1" budget should have max_cost_usd 50.0 Scenario: Service configure org budget Given a cost budget service When I configure org "org-1" with max_cost_usd 200.0 Then org "org-1" accumulator should have max_cost_usd 200.0 Scenario: Service rejects empty session_id Given a cost budget service When I try to configure session "" with max_cost_usd 10.0 Then a cost budget validation error should be raised Scenario: Service rejects empty org_id Given a cost budget service When I try to configure org "" with max_cost_usd 10.0 Then a cost budget validation error should be raised Scenario: Service rejects negative session max_cost Given a cost budget service When I try to configure session "bad" with max_cost_usd -1.0 Then a cost budget validation error should be raised Scenario: Service rejects negative org max_cost Given a cost budget service When I try to configure org "bad" with max_cost_usd -1.0 Then a cost budget validation error should be raised Scenario: Service budget hierarchy allows when within all limits Given a cost budget service with warning threshold 0.8 And session "s1" configured with max_cost_usd 100.0 And org "o1" configured with max_cost_usd 500.0 And session "s1" associated with org "o1" When I check budget hierarchy for session "s1" with plan_cost 10.0 Then the budget check should be allowed And the budget check warning should be false Scenario: Service budget hierarchy blocks at session level Given a cost budget service And session "s2" configured with max_cost_usd 10.0 When I record plan cost 8.0 for session "s2" And I check budget hierarchy for session "s2" with plan_cost 5.0 Then the budget check should be denied And the budget check exceeded_level should be "session" Scenario: Service budget hierarchy blocks at org level Given a cost budget service And session "s3" configured with max_cost_usd 100.0 And org "o2" configured with max_cost_usd 10.0 And session "s3" associated with org "o2" When I record plan cost 8.0 for session "s3" And I check budget hierarchy for session "s3" with plan_cost 5.0 Then the budget check should be denied And the budget check exceeded_level should be "org" Scenario: Service budget hierarchy blocks at plan level Given a cost budget service And session "s4" configured with max_cost_usd 100.0 When I check budget hierarchy for session "s4" with plan_cost 5.0 and plan_budget 3.0 and plan_spent 0.0 Then the budget check should be denied And the budget check exceeded_level should be "plan" Scenario: Service budget hierarchy emits warning at threshold Given a cost budget service with warning threshold 0.5 And session "sw1" configured with max_cost_usd 100.0 When I record plan cost 60.0 for session "sw1" And I check budget hierarchy for session "sw1" with plan_cost 1.0 Then the budget check should be allowed And the budget check warning should be true Scenario: Service record plan cost Given a cost budget service And session "rc1" configured with max_cost_usd 100.0 When I record plan cost 25.0 for session "rc1" Then session "rc1" budget total_cost should be 25.0 Scenario: Service record plan cost rejects empty session_id Given a cost budget service When I try to record plan cost 10.0 for session "" Then a cost budget validation error should be raised Scenario: Service record plan cost rejects negative cost Given a cost budget service And session "neg1" configured with max_cost_usd 100.0 When I try to record plan cost -5.0 for session "neg1" Then a cost budget validation error should be raised Scenario: Service record plan cost rejects non-numeric cost Given a cost budget service And session "te1" configured with max_cost_usd 100.0 When I try to record plan cost with type error for session "te1" Then a cost budget type error should be raised Scenario: Service check hierarchy rejects empty session_id Given a cost budget service When I try to check budget hierarchy for session "" with plan_cost 1.0 Then a cost budget validation error should be raised Scenario: Service check hierarchy rejects negative plan_cost Given a cost budget service And session "hn1" configured with max_cost_usd 100.0 When I try to check budget hierarchy for session "hn1" with plan_cost -1.0 Then a cost budget validation error should be raised Scenario: Service check hierarchy rejects non-numeric plan_cost Given a cost budget service And session "hte1" configured with max_cost_usd 100.0 When I try to check budget hierarchy for session "hte1" with plan_cost type error Then a cost budget type error should be raised Scenario: Service check hierarchy rejects negative plan_spent Given a cost budget service And session "hps1" configured with max_cost_usd 100.0 When I try to check budget hierarchy for session "hps1" with plan_cost 1.0 and plan_spent -1.0 Then a cost budget validation error should be raised Scenario: Service remove session cleanup Given a cost budget service And session "rm1" configured with max_cost_usd 100.0 When I remove session "rm1" from cost budget service Then session "rm1" budget should be None Scenario: Service remove org cleanup Given a cost budget service And org "rmo1" configured with max_cost_usd 100.0 When I remove org "rmo1" from cost budget service Then org "rmo1" accumulator should be None Scenario: Service get_session_budget rejects empty id Given a cost budget service When I try to get session budget for "" Then a cost budget validation error should be raised Scenario: Service get_org_accumulator rejects empty id Given a cost budget service When I try to get org accumulator for "" Then a cost budget validation error should be raised Scenario: Service rejects invalid warning threshold too high When I try to create a cost budget service with warning threshold 1.5 Then a cost budget validation error should be raised Scenario: Service rejects invalid warning threshold too low When I try to create a cost budget service with warning threshold -0.1 Then a cost budget validation error should be raised Scenario: Service rejects non-numeric warning threshold When I try to create a cost budget service with non-numeric warning threshold Then a cost budget type error should be raised # ---- AutonomyGuardrailService budget hierarchy integration ---- Scenario: Guardrail service check budget hierarchy with no session Given a guardrail service with cost budget service And guardrails configured for plan "p1" with tool_budget 50.0 When I check budget hierarchy for plan "p1" with tool_cost 10.0 Then the budget hierarchy check should be allowed Scenario: Guardrail service check budget hierarchy blocks at plan Given a guardrail service with cost budget service And guardrails configured for plan "p2" with tool_budget 5.0 When I check budget hierarchy for plan "p2" with tool_cost 10.0 Then the budget hierarchy check should be denied And the hierarchy exceeded_level should be "plan" Scenario: Guardrail service check budget hierarchy blocks at session Given a guardrail service with cost budget service And session "gs1" configured on cost budget service with max_cost_usd 10.0 And plan "gp1" associated with session "gs1" When I record guardrail plan cost 8.0 for plan "gp1" And I check budget hierarchy for plan "gp1" with tool_cost 5.0 Then the budget hierarchy check should be denied And the hierarchy exceeded_level should be "session" Scenario: Guardrail service record plan cost to session Given a guardrail service with cost budget service And session "grc1" configured on cost budget service with max_cost_usd 100.0 And plan "gp3" associated with session "grc1" And guardrails configured for plan "gp3" with tool_budget 50.0 When I record guardrail plan cost 10.0 for plan "gp3" Then plan "gp3" guardrails budget_spent should be 10.0 Scenario: Guardrail service associate plan rejects empty plan_id Given a guardrail service with cost budget service When I try to associate plan "" with session "s1" Then a cost budget validation error should be raised Scenario: Guardrail service associate plan rejects empty session_id Given a guardrail service with cost budget service When I try to associate plan "p1" with session "" Then a cost budget validation error should be raised Scenario: Guardrail service check hierarchy rejects empty plan_id Given a guardrail service with cost budget service When I try to check budget hierarchy for plan "" with tool_cost 1.0 Then a cost budget validation error should be raised Scenario: Guardrail service check hierarchy rejects negative tool_cost Given a guardrail service with cost budget service When I try to check budget hierarchy for plan "p1" with tool_cost -1.0 Then a cost budget validation error should be raised Scenario: Guardrail service check hierarchy rejects non-numeric tool_cost Given a guardrail service with cost budget service When I try to check budget hierarchy for plan "p1" with non-numeric tool_cost Then a cost budget type error should be raised Scenario: Guardrail service record cost rejects empty plan_id Given a guardrail service with cost budget service When I try to record guardrail plan cost 1.0 for plan "" Then a cost budget validation error should be raised Scenario: Guardrail service record cost rejects negative Given a guardrail service with cost budget service When I try to record guardrail plan cost -1.0 for plan "p1" Then a cost budget validation error should be raised Scenario: Guardrail service record cost rejects non-numeric Given a guardrail service with cost budget service When I try to record guardrail plan cost with type error for plan "p1" Then a cost budget type error should be raised Scenario: Guardrail service remove plan cleans up session map Given a guardrail service with cost budget service And plan "rp1" associated with session "rs1" When I remove plan "rp1" from guardrail service Then plan "rp1" should not be associated with any session # ---- Settings ---- Scenario: Settings default budget fields When I load default settings Then session_max_cost_usd should be None And org_max_cost_usd should be None And budget_warning_threshold should be 0.8 # ---- Session model cost_budget integration ---- Scenario: Session model has cost_budget field When I create a session with cost budget max_cost_usd 50.0 Then the session cost_budget max_cost_usd should be 50.0 And the session cost_budget total_cost should be 0.0 Scenario: Session as_cli_dict includes cost_budget When I create a session with cost budget max_cost_usd 100.0 And I record 40.0 to the session cost budget And I get the session cli dict Then the cli dict should contain "cost_budget" key And the cli dict cost_budget total_cost should be 40.0 And the cli dict cost_budget max_cost_usd should be 100.0 And the cli dict cost_budget utilization should be "40%" Scenario: Service budget hierarchy with event bus emits warning Given a cost budget service with mock event bus and warning threshold 0.5 And session "ew1" configured with max_cost_usd 100.0 When I record plan cost 60.0 for session "ew1" And I check budget hierarchy for session "ew1" with plan_cost 1.0 Then the mock event bus should have received a BUDGET_WARNING event Scenario: Service budget hierarchy with event bus emits exceeded Given a cost budget service with mock event bus and warning threshold 0.8 And session "ee1" configured with max_cost_usd 10.0 When I record plan cost 8.0 for session "ee1" And I check budget hierarchy for session "ee1" with plan_cost 5.0 Then the mock event bus should have received a BUDGET_EXCEEDED event Scenario: Service configure session with org_id association Given a cost budget service And org "ao1" configured with max_cost_usd 200.0 When I configure session "as1" with max_cost_usd 50.0 and org_id "ao1" And I record plan cost 5.0 for session "as1" Then org "ao1" accumulator total_cost should be 5.0 Scenario: Service configure session rejects empty org_id Given a cost budget service When I try to configure session "s1" with max_cost_usd 10.0 and empty org_id Then a cost budget validation error should be raised Scenario: Uncapped session budget utilization is none Given a session cost budget with no cap Then the session budget utilization should be None And the session budget remaining should be None And the session budget is_exceeded should be false Scenario: Uncapped org accumulator utilization is none Given an org accumulator for org "unc-org" with no cap Then the org accumulator utilization should be None And the org accumulator remaining should be None And the org accumulator is_exceeded should be false Scenario: Uncapped session budget would_exceed is always false Given a session cost budget with no cap Then the session budget would_exceed 999.0 should be false Scenario: Uncapped org accumulator would_exceed is always false Given an org accumulator for org "unc-org2" with no cap Then the org accumulator would_exceed 999.0 should be false Scenario: Service budget hierarchy with no budget service on guardrail Given a guardrail service without cost budget service And guardrails configured for plan "np1" with tool_budget 50.0 And plan "np1" associated with session "ns1" on guardrail service When I check budget hierarchy for plan "np1" with tool_cost 10.0 Then the budget hierarchy check should be allowed Scenario: Service budget hierarchy no guardrails no session Given a guardrail service with cost budget service When I check budget hierarchy for plan "unp1" with tool_cost 10.0 Then the budget hierarchy check should be allowed Scenario: Service budget warning only emitted once per session Given a cost budget service with mock event bus and warning threshold 0.5 And session "once1" configured with max_cost_usd 100.0 When I record plan cost 60.0 for session "once1" And I check budget hierarchy for session "once1" with plan_cost 1.0 And I check budget hierarchy for session "once1" with plan_cost 1.0 Then the mock event bus should have received exactly 1 BUDGET_WARNING event Scenario: BudgetCheckResult model is frozen When I create a budget check result allowed=true Then modifying the budget check result should raise an error