GCAP-SPEC-FUNCTION-DESCRIPTOR-0001 implementation. Mirrors connector runtime pattern exactly. FunctionPlugin — trigger_events, handle(), descriptor(), knative_manifest() FunctionRegistry — trigger_index for event-driven routing FunctionRuntime — invoke() + dispatch() with Chronicle lineage governed_function decorator — SDK surface for function authors BillingProcessor — GSAP_CR_RECEIVED → billable event with Chronicle CID EchoFunction — dev/test API: /functions/ catalogue, invoke, dispatch, manifest, health 8 tests passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
62 lines
2 KiB
Python
62 lines
2 KiB
Python
"""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
|