"""BillingProcessor — governed billing drain function per §5.""" from __future__ import annotations from typing import Any from gsap_broker.functions.base import FunctionContext, FunctionPlugin, FunctionResult RATE_CARD: dict[str, float] = { "connector_invocation": 0.002, "function_invocation": 0.001, "chronicle_event": 0.0005, "gsap_ac_issued": 0.003, "gsap_cr_completed": 0.005, } class BillingProcessor(FunctionPlugin): function_id = "billing-processor" corpus_entry_cid = "sha256:" + "b" * 64 capability_mask = 3 # MUTATE trigger_events = ["GSAP_CR_RECEIVED"] accord_template = "" gsap_required = False chronicle_enabled = True max_duration_seconds = 10 display_name = "Billing Processor" description = "Governed billing drain — only bills completed outcomes with Chronicle CID reference." version = "0.1.0" async def handle(self, event: dict[str, Any], context: FunctionContext) -> FunctionResult: outcome = event.get("outcome", "") if outcome != "completed": return FunctionResult( success=True, data={"billed": False, "reason": f"Outcome '{outcome}' is not billable"}, metadata={"function_id": self.function_id}, ) event_type = event.get("event_type", "gsap_cr_completed") rate = RATE_CARD.get(event_type, RATE_CARD["gsap_cr_completed"]) quantity = event.get("quantity", 1) amount = rate * quantity billing_record = { "billed": True, "event_type": event_type, "rate": rate, "quantity": quantity, "amount": amount, "chronicle_cid": context.trigger_event_cid or event.get("chronicle_cid", ""), "invocation_id": context.invocation_id, } return FunctionResult( success=True, data=billing_record, metadata={"function_id": self.function_id}, ) def health_check(self) -> bool: return True