Documentation
¶
Overview ¶
Package billing defines the minimal typed external monetary host binding.
An external billing integration supplies one Binding: a stable identity and version plus typed ports for the cheap pre-route credit screen, the bounded quote and atomic exposure admission, the terminal evidence handoff with a durable acknowledgement, and explicit owned-resource lifecycle registration. Adapters translate these public DTOs to the existing internal billing services; the binding itself carries no SQL handles, executors, request bodies, or provider-shaped payloads.
The provider-neutral observation/sideband DTOs and the Rater, Quoter, StatementImporter, and ReconciliationReader contracts remain defined in pkg/lipsdk/metering and pkg/lipsdk/economics. This package reuses them and introduces no generic provider-shaped normalizer port and no service-map or any-typed payload.
Import DAG: billing -> economics -> metering, billing -> scope (no cycles).
Boundary rules:
- Must not import internal/*, database/sql, net/http, Bun/driver types, or provider SDKs and concrete plugins.
- DTOs are immutable-style public values using only public packages/types.
- No any, no generic maps standing in for typed APIs.
Index ¶
- Constants
- Variables
- func ValidateBindings(bindings []Binding) error
- type Binding
- type BindingScope
- type BorrowedRef
- type CreditDecision
- type CreditScreenInput
- type CreditScreenResult
- type CreditScreener
- type ExposureAdmissionInput
- type ExposureAdmitter
- type ExposureHandle
- type Lifecycle
- type OwnedResource
- type TerminalAck
- type TerminalEnvelope
- type TerminalOutcome
- type TerminalSink
- type TerminalWorkload
Constants ¶
const ( // MaxExecutionLimits bounds finite candidate/work quantities per admission. MaxExecutionLimits = 128 // MaxUnitReservations bounds non-monetary unit reservations per admission. MaxUnitReservations = 128 )
const ( // MaxOwnedResources bounds binding-owned resources per lifecycle. MaxOwnedResources = 64 // MaxBorrowedRefs bounds declared borrowed handles per lifecycle. MaxBorrowedRefs = 64 )
const ( // MaxBindingIDLength bounds the stable external binding identifier. MaxBindingIDLength = 128 // MaxIdentityBytes bounds account, store, envelope, and resource IDs. MaxIdentityBytes = 512 // MaxReasonBytes bounds human-readable decision reasons. MaxReasonBytes = 512 )
const ( // TerminalEnvelopeVersionV1 is the first version of the terminal envelope. TerminalEnvelopeVersionV1 uint32 = 1 // MaxObservationsPerEnvelope bounds neutral evidence per terminal handoff. MaxObservationsPerEnvelope = 1024 // MaxExpectedBLegIDs bounds call-closure B-leg coverage per envelope. MaxExpectedBLegIDs = 1024 )
const ( // BindingVersionV1 is the first version of the external billing binding. BindingVersionV1 uint32 = 1 )
Variables ¶
var ( // ErrInvalidAdmission identifies a malformed exposure-admission DTO. ErrInvalidAdmission = errors.New("billing: invalid exposure admission") // ErrQuoteMismatch identifies a structurally valid quote that names a // different subject, store, or frozen snapshot than requested. It must // be rejected before atomic admission, never forwarded. ErrQuoteMismatch = errors.New("billing: quote does not match requested subject") // ErrAdmissionMismatch identifies a structurally valid handle that names // a different store, call, or quote than admitted. It cannot authorize // the requested call. ErrAdmissionMismatch = errors.New("billing: admission handle does not match request") )
var ( // ErrInvalidBinding identifies a malformed binding envelope. ErrInvalidBinding = errors.New("billing: invalid binding") // ErrInvalidBindingID identifies a missing or malformed binding ID. ErrInvalidBindingID = errors.New("billing: invalid binding ID") // ErrUnsupportedBindingVersion identifies an unknown binding version. ErrUnsupportedBindingVersion = errors.New("billing: unsupported binding version") // ErrMissingCreditScreen identifies an absent credit-screen port. ErrMissingCreditScreen = errors.New("billing: credit screen port is required") // ErrMissingQuoter identifies an absent quote port. ErrMissingQuoter = errors.New("billing: quoter port is required") // ErrMissingAdmission identifies an absent exposure-admission port. ErrMissingAdmission = errors.New("billing: exposure admission port is required") // ErrMissingTerminal identifies an absent terminal handoff port. ErrMissingTerminal = errors.New("billing: terminal port is required") // ErrDuplicateMonetaryBinding rejects a second monetary binding. Ordinary // non-money authority registrations may coexist for distinct quotas, but // they must never create a second monetary authority. ErrDuplicateMonetaryBinding = errors.New("billing: duplicate monetary binding") )
var ( // ErrInvalidCreditScreen identifies a malformed credit-screen DTO. ErrInvalidCreditScreen = errors.New("billing: invalid credit screen") // ErrCreditResultMismatch identifies a structurally valid result that // answers a different store or account. It is never a decision for the // requested account, whatever its allow/deny value. ErrCreditResultMismatch = errors.New("billing: credit result does not match request") )
var ( // ErrInvalidTerminal identifies a malformed terminal handoff DTO. ErrInvalidTerminal = errors.New("billing: invalid terminal handoff") // ErrTerminalAckMismatch identifies a structurally valid acknowledgement // that answers a different envelope. Store and envelope identity must // match the sent envelope exactly; a foreign ack is never durable success. ErrTerminalAckMismatch = errors.New("billing: terminal acknowledgement does not match envelope") )
var ErrInvalidBindingScope = errors.New("billing: invalid binding scope")
ErrInvalidBindingScope identifies a missing or malformed composition-time economics identity.
var ErrInvalidLifecycle = errors.New("billing: invalid lifecycle")
ErrInvalidLifecycle identifies a malformed lifecycle declaration.
Functions ¶
func ValidateBindings ¶
ValidateBindings validates each candidate binding and enforces the single-monetary-authority rule: at most one monetary binding may be published. An empty set is valid and keeps the host non-money.
Types ¶
type Binding ¶
type Binding struct {
ID string
Version uint32
Scope BindingScope
CreditScreen CreditScreener
Quoter economics.Quoter
Admission ExposureAdmitter
Terminal TerminalSink
Lifecycle Lifecycle
}
Binding is the minimal typed external monetary host binding. It carries a stable identity and version, complete cheap-screen/quote-admit/terminal ports, and explicit owned-resource lifecycle registration. Public rater and statement/reconciliation ports stay separate in pkg/lipsdk/economics; workers consume them after terminal persistence, not through this binding.
func (Binding) IsMonetary ¶
IsMonetary reports that the binding owns the monetary authority. It lets a future host composition reject a second monetary binding while ordinary non-money authority registrations coexist for distinct quotas.
type BindingScope ¶
type BindingScope struct {
StoreID string `json:"store_id"`
Tariff economics.RatingSnapshotRef `json:"tariff"`
Policy economics.PolicySnapshotRef `json:"policy"`
}
BindingScope carries the composition-time economics identity owned by the binding: the trusted store and the frozen tariff and policy snapshots the host binding translates into quote, admission, credit-screen, and terminal DTOs. Adapters never invent these identities; the binding declares them.
func (BindingScope) Clone ¶
func (s BindingScope) Clone() BindingScope
Clone returns an independent copy of the scope.
func (BindingScope) Validate ¶
func (s BindingScope) Validate() error
Validate requires the store identity and the frozen snapshot references.
type BorrowedRef ¶
BorrowedRef declares one borrowed store or resource handle. Borrowed handles are never implicitly closed: the type offers no close entry point, so host cleanup cannot dispose a store it does not own.
func (BorrowedRef) Validate ¶
func (r BorrowedRef) Validate() error
Validate requires borrowed identity with an optional bounded kind label.
type CreditDecision ¶
type CreditDecision string
CreditDecision is the typed outcome of the cheap pre-route credit screen.
const ( // CreditAllow permits route planning to proceed. CreditAllow CreditDecision = "allow" // CreditDeny stops the request before provider execution. CreditDeny CreditDecision = "deny" // CreditDegraded permits execution with explicitly reduced guarantees. CreditDegraded CreditDecision = "degraded" )
func (CreditDecision) IsKnown ¶
func (d CreditDecision) IsKnown() bool
IsKnown reports whether d is a documented credit decision.
type CreditScreenInput ¶
type CreditScreenInput struct {
Scope scope.PrincipalScopeView `json:"scope"`
StoreID string `json:"store_id"`
AccountID string `json:"account_id"`
Policy economics.PolicySnapshotRef `json:"policy"`
}
CreditScreenInput carries the trusted customer scope, the account reference, and the frozen policy version for one cheap pre-route credit check.
func (CreditScreenInput) Clone ¶
func (in CreditScreenInput) Clone() CreditScreenInput
Clone returns an independent copy of the input.
func (CreditScreenInput) Validate ¶
func (in CreditScreenInput) Validate() error
Validate requires trusted scope, store/account identity, and policy version.
type CreditScreenResult ¶
type CreditScreenResult struct {
Decision CreditDecision `json:"decision"`
Reason string `json:"reason,omitempty"`
StoreID string `json:"store_id"`
AccountID string `json:"account_id"`
}
CreditScreenResult is the typed allow/deny/degraded outcome. Reason is a bounded human-readable label, never raw account state.
func (CreditScreenResult) Clone ¶
func (r CreditScreenResult) Clone() CreditScreenResult
Clone returns an independent copy of the result.
func (CreditScreenResult) MatchesInput ¶
func (r CreditScreenResult) MatchesInput(in CreditScreenInput) bool
MatchesInput reports whether the result answers exactly the submitted store and account. The decision value is irrelevant to identity.
func (CreditScreenResult) Validate ¶
func (r CreditScreenResult) Validate() error
Validate requires a known decision and store/account identity.
type CreditScreener ¶
type CreditScreener interface {
Check(ctx context.Context, in CreditScreenInput) (CreditScreenResult, error)
}
CreditScreener is the cheap pre-route credit gate. It performs a bounded account read and never posts financial state.
type ExposureAdmissionInput ¶
type ExposureAdmissionInput struct {
Subject metering.SubjectRef `json:"subject"`
Scope scope.PrincipalScopeView `json:"scope"`
AccountID string `json:"account_id"`
Quote economics.ExposureQuote `json:"quote"`
ExecutionLimits []economics.Limit `json:"execution_limits"`
UnitReservations []economics.UnitBound `json:"unit_reservations,omitempty"`
}
ExposureAdmissionInput carries one frozen quote, the call identity, the trusted customer scope and credited account, finite execution limits, and unit reservations for atomic exposure admission.
func (ExposureAdmissionInput) Clone ¶
func (in ExposureAdmissionInput) Clone() ExposureAdmissionInput
Clone returns an independent copy of the input.
func (ExposureAdmissionInput) Validate ¶
func (in ExposureAdmissionInput) Validate() error
Validate requires call identity, trusted customer scope and credited account for per-customer allowance binding, a frozen quote bound to exactly the requested subject, and at least one finite execution limit.
type ExposureAdmitter ¶
type ExposureAdmitter interface {
Admit(ctx context.Context, in ExposureAdmissionInput) (ExposureHandle, error)
}
ExposureAdmitter is the atomic operational exposure admission authority. It consumes one frozen quote and finite execution limits and returns an admitted handle or a typed rejection.
type ExposureHandle ¶
type ExposureHandle struct {
StoreID string `json:"store_id"`
BillingCallID string `json:"billing_call_id"`
ExposureID string `json:"exposure_id"`
QuoteID string `json:"quote_id"`
}
ExposureHandle is the admitted-exposure identity returned by atomic admission. It carries store-scoped IDs only.
func (ExposureHandle) Clone ¶
func (h ExposureHandle) Clone() ExposureHandle
Clone returns an independent copy of the handle.
func (ExposureHandle) MatchesAdmission ¶
func (h ExposureHandle) MatchesAdmission(in ExposureAdmissionInput) bool
MatchesAdmission reports whether the handle authorizes exactly the admitted request: store and call must equal the admission subject, and a carried quote ID must equal the admitted quote. The quote-ID check applies only when the quote itself carries an ID.
func (ExposureHandle) Validate ¶
func (h ExposureHandle) Validate() error
Validate requires complete store-scoped exposure identity.
type Lifecycle ¶
type Lifecycle struct {
Owned []OwnedResource
Borrowed []BorrowedRef
}
Lifecycle is the explicit owned-resource registration for one binding. Owned resources are started and closed once by the host; borrowed refs are declared for attribution and are never closed by host cleanup.
type OwnedResource ¶
type OwnedResource struct {
ID string
Start func(ctx context.Context) error
Close func(ctx context.Context) error
}
OwnedResource is one binding-owned resource registration. Owned resources start and close exactly once under host cleanup; a start failure unwinds already-started owned resources through the same host cleanup path.
func (OwnedResource) Validate ¶
func (r OwnedResource) Validate() error
Validate requires resource identity and both start and close callbacks.
type TerminalAck ¶
type TerminalAck struct {
StoreID string `json:"store_id"`
EnvelopeID string `json:"envelope_id"`
Revision uint64 `json:"revision"`
}
TerminalAck is the idempotent durable acknowledgement for one envelope.
func (TerminalAck) Clone ¶
func (a TerminalAck) Clone() TerminalAck
Clone returns an independent copy of the acknowledgement.
func (TerminalAck) MatchesEnvelope ¶
func (a TerminalAck) MatchesEnvelope(env TerminalEnvelope) bool
MatchesEnvelope reports whether the acknowledgement answers exactly the sent envelope, identified by store and envelope ID.
func (TerminalAck) Validate ¶
func (a TerminalAck) Validate() error
Validate requires the acknowledged envelope identity and a nonzero durable revision.
type TerminalEnvelope ¶
type TerminalEnvelope struct {
Version uint32 `json:"version"`
EnvelopeID string `json:"envelope_id"`
StoreID string `json:"store_id"`
Scope scope.PrincipalScopeView `json:"scope"`
Subject metering.SubjectRef `json:"subject"`
Correlation metering.CorrelationV2 `json:"correlation"`
Outcome TerminalOutcome `json:"outcome"`
AttemptSeq uint64 `json:"attempt_seq"`
AccountID string `json:"account_id,omitempty"`
ALegID string `json:"a_leg_id,omitempty"`
SubmissionID string `json:"submission_id,omitempty"`
Workload *TerminalWorkload `json:"workload,omitempty"`
ExpectedBLegIDs []string `json:"expected_b_leg_ids,omitempty"`
Tariff economics.RatingSnapshotRef `json:"tariff"`
Policy economics.PolicySnapshotRef `json:"policy"`
Observations []metering.Observation `json:"observations,omitempty"`
ParentWorkID string `json:"parent_work_id,omitempty"`
PayloadHash string `json:"payload_hash"`
}
TerminalEnvelope is the public terminal evidence handoff. It carries format version, store/customer scope, call/attempt closure identity and outcome, the authoritative attempt sequence, frozen rate/policy references, neutral V2 observations, parent/workload coverage, and a payload hash. It contains no SQL driver, executor pointer, request body, or mutable service map.
func (TerminalEnvelope) Clone ¶
func (e TerminalEnvelope) Clone() TerminalEnvelope
Clone returns an independent copy of the envelope. Coverage order and the authoritative sequence are preserved as carried; only the slices and the workload pointer are deep-copied, never reordered.
func (TerminalEnvelope) Validate ¶
func (e TerminalEnvelope) Validate() error
Validate checks envelope identity, call/leg lineage, frozen references, neutral evidence, closure coverage, and payload integrity.
Lineage rules: B-leg closures require A-leg identity and a positive authoritative attempt sequence; call closures require the customer account and A-leg identity but carry no leg sequence. Submission and workload are optional attribution present only when the closure carries them.
type TerminalOutcome ¶
type TerminalOutcome string
TerminalOutcome classifies the execution closure carried by an envelope.
const ( // TerminalCompleted marks successful execution closure. TerminalCompleted TerminalOutcome = "completed" // TerminalFailed marks failed execution closure; incurred usage remains. TerminalFailed TerminalOutcome = "failed" // TerminalCanceled marks canceled execution closure; incurred usage remains. TerminalCanceled TerminalOutcome = "canceled" )
func (TerminalOutcome) IsKnown ¶
func (o TerminalOutcome) IsKnown() bool
IsKnown reports whether o is a documented terminal outcome.
type TerminalSink ¶
type TerminalSink interface {
AppendTerminal(ctx context.Context, envelope TerminalEnvelope) (TerminalAck, error)
}
TerminalSink is the terminal evidence handoff. It durably persists the envelope and returns an idempotent acknowledgement; it is never a best-effort observer.
type TerminalWorkload ¶
type TerminalWorkload struct {
Class string `json:"class,omitempty"`
Role string `json:"role,omitempty"`
}
TerminalWorkload carries parent/workload correlation for one terminal envelope. Class and role are bounded safe labels, never request content. A nil workload means the closure carries no workload attribution.
func (TerminalWorkload) Clone ¶
func (w TerminalWorkload) Clone() TerminalWorkload
Clone returns an independent copy of the workload.
func (TerminalWorkload) IsZero ¶
func (w TerminalWorkload) IsZero() bool
IsZero reports whether the workload carries no attribution.
func (TerminalWorkload) Validate ¶
func (w TerminalWorkload) Validate() error
Validate checks the bounded workload labels.