feat(engine): pluggable SaaS pricing shapes — flat_subscription, per_unit_flat, free_tier, transactional (#241) - #242
Merged
Conversation
…unit_flat, free_tier, transactional (#241) Add a pluggable SaaS pricing-handler registry (SaaSPricingRegistry) with four built-in shapes: - flat_subscription — fixed monthly fee, charged when enabled (e.g. 9/mo per custom domain). - per_unit_flat — $X × count (e.g. 25/mo per SSO connection, /mo per org). - free_tier — first N units free, then /unit overage (e.g. 1M MAU free, bash.01/MAU above). Supports optional stepped tiers for graduated overage. - transactional — the existing percentage + per-transaction + per-call shape, preserved for vocabulary completeness. A cost-model node declares the shape per metric via a 'shape' field: workos: provider: workos usageMetrics: SSO-Connection: { unit: Conn, value: 2, shape: per_unit_flat, rate: 125.0 } The engine dispatches to the shape handler before the catalog / embedded pricingRates path. An unknown shape falls back to the existing path (opt-in, backward-compatible). Third-party packages register additional shapes via the infra_cost_model.saas_handlers entry-point group. Design follows existing patterns — registry class (like ResourceRegistry), shape computed per-metric in _compute_flat_cost and _compute_tiered_cost, quantity = derived invocation count × value (usage-driven) or direct value (fixed/flatOverride). Co-authored-by: silent-orca-64 <silent-orca-64@pi-agent.local>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #241 by promoting the external-node extension point from a single transactional formula into a pluggable SaaS pricing-handler registry. Four built-in shapes cover the most common SaaS billing models; third-party packages add more via
infra_cost_model.saas_handlersentry-points.Design
Each shape is a
(quantity, params) -> monthly_cost_usdcallable. The model declares which shape a metric uses:so free-tier boundaries and per-unit rates live in the model, not in Python.
Built-in shapes
flat_subscriptionper_unit_flatfree_tierfreeunits at $0, thenoverage$/unit, optional steppedtierstransactionalEngine integration
Both
_compute_flat_costand_compute_tiered_costdispatch toSaaSPricingRegistry.compute()when a metric declares ashapefield — before the catalog / embeddedpricingRatesfallback path. An unknown shape returnsNoneinstead of raising: backward-compatible by construction.Entry-point discovery
discover_entry_point_handlers()scansinfra_cost_model.saas_handlersat import time. The four built-in shapes themselves are registered as entry-points.What this does NOT do
pricingRatespath (Principle 13).ExternalServiceRegistryAPI.Tests
tests/test_saas_pricing_shapes.py— 32 new tests covering all shapes, registry, engine integration, backward compatibility, and entry-point discovery. All 51 external tests pass, zero regressions.— silent-orca-64