Related: #1511 , #1522 , #1524 , #1525 , #1541 , #1546 , #1570
Priority
P1 — add after the underlying billing, metering, credit, and quantity read models expose stable state.
Problem
@croco/lifecycle-core can evaluate generic SaaS signals and dispatch actions, but applications still need to invent their own event names, payload shapes, threshold semantics, cooldown rules, and recovery behavior for common monetization moments such as trial expiry, payment delinquency, usage thresholds, credit depletion, delivery lag, and seat drift.
This leads to incompatible recipes across applications and makes lifecycle automation difficult to inspect, test, or expose through admin tooling. Provider-specific webhook payloads also risk leaking into product rules instead of being normalized at the billing boundary.
Desired outcome
Add a small provider-neutral monetization signal vocabulary and tested reference recipes that applications can opt into without turning lifecycle-core into a billing engine or a visual workflow product.
await lifecycle . evaluate (
createUsageThresholdCrossedSignal ( {
tenantId,
meterKey : "ai.tokens" ,
planVersionRef,
threshold : 0.8 ,
consumed : 800_000 ,
limit : 1_000_000 ,
periodEndsAt,
} ) ,
) ;
Scope
Signal factories
Add stable factories and payload contracts for:
billing.trial.ending
billing.subscription.past_due
billing.subscription.recovered
billing.usage.threshold_crossed
billing.credit.balance_low
billing.credit.exhausted
billing.usage.delivery_lagging
billing.usage.sync_drifted
billing.seat.quantity_drifted
Every signal must include:
tenant identity;
immutable PlanVersionRef where applicable;
effective timestamp and source timestamp;
deterministic signal identity or idempotency material;
provider-neutral reason/status fields;
safe evidence suitable for diagnostics and dry-run inspection;
explicit recovery correlation where a recovered signal exists.
Threshold semantics
Define one-shot threshold crossing semantics rather than emitting on every usage record above the threshold.
Support ordered threshold levels such as 0.5, 0.8, 1.0, and configured overage bands.
Scope crossings by tenant, meter, plan version, and billing period.
Reset crossing state only when the billing period or governing plan version changes.
Keep hard quota enforcement in entitlements-core; lifecycle signals are informational/action triggers only.
Reference recipes
Provide code-declared recipes for:
trial ending reminders;
past-due grace-period notification and CS follow-up;
usage 80% upgrade prompt;
quota reached operator/customer notification;
low-credit warning;
billable usage delivery backlog escalation before period close;
provider/local usage drift escalation;
licensed seat quantity drift escalation.
Recipes must:
use existing lifecycle cooldown and idempotency semantics;
declare required context and supported actions explicitly;
remain provider-neutral;
be installable individually rather than auto-enabled;
include recovery behavior where appropriate;
work with [lifecycle-core] Add versioned rule activation and dry-run evaluation #1546 versioned activation and dry-run without special cases.
Composition boundaries
Billing, metering, credits, and membership adapters normalize their state into these signals; lifecycle-core must not import provider SDKs.
Do not duplicate payment retry schedules, invoice collection, or tax behavior owned by the provider.
Do not change entitlements directly from signal factories; applications may register audited actions that do so under explicit policy.
Diagnostics and ContractGraph
Include signal descriptors and recipe IDs in deterministic lifecycle artifacts.
Expose recent monetization signal counts, suppressed duplicate crossings, failed actions, and latest recovery state.
Ensure sensitive customer or payment data is excluded from default evidence.
Add ContractGraph/runtime diagnostics when an enabled recipe requires an unavailable signal source or action adapter.
Acceptance criteria
All signal factories produce deterministic, provider-neutral descriptors and stable public types.
Repeated usage records above one threshold emit one crossing per billing period and plan version.
Crossing a higher threshold after a lower one emits the higher threshold exactly once.
A period or plan-version transition resets threshold state deterministically.
Recovery signals correlate to the original delinquency/drift condition without replaying completed actions.
Reference recipes are opt-in, individually testable, and compatible with versioned activation/dry-run from [lifecycle-core] Add versioned rule activation and dry-run evaluation #1546 .
Provider webhook payloads and provider IDs do not leak into public lifecycle rule predicates.
Signal evidence is redacted and safe for diagnostics/admin presentation by default.
Missing source/action capabilities fail explicitly rather than silently disabling a recipe.
Tests cover duplicate events, out-of-order provider events, threshold races, billing-period rollover, plan migration, recovery, cooldown, and action failure.
README, API docs, public API snapshots, lifecycle artifacts, and changesets are updated.
Verification
Non-goals
Implementing a campaign builder or customer messaging UI.
Owning provider payment retry schedules or dunning decisions.
Predictive churn scoring or experimentation allocation.
Automatically enabling lifecycle actions in generated applications.
Replacing billing, metering, entitlement, credit, or seat reconciliation state machines.
Related: #1511, #1522, #1524, #1525, #1541, #1546, #1570
Priority
P1 — add after the underlying billing, metering, credit, and quantity read models expose stable state.
Problem
@croco/lifecycle-corecan evaluate generic SaaS signals and dispatch actions, but applications still need to invent their own event names, payload shapes, threshold semantics, cooldown rules, and recovery behavior for common monetization moments such as trial expiry, payment delinquency, usage thresholds, credit depletion, delivery lag, and seat drift.This leads to incompatible recipes across applications and makes lifecycle automation difficult to inspect, test, or expose through admin tooling. Provider-specific webhook payloads also risk leaking into product rules instead of being normalized at the billing boundary.
Desired outcome
Add a small provider-neutral monetization signal vocabulary and tested reference recipes that applications can opt into without turning
lifecycle-coreinto a billing engine or a visual workflow product.Scope
Signal factories
Add stable factories and payload contracts for:
billing.trial.endingbilling.subscription.past_duebilling.subscription.recoveredbilling.usage.threshold_crossedbilling.credit.balance_lowbilling.credit.exhaustedbilling.usage.delivery_laggingbilling.usage.sync_driftedbilling.seat.quantity_driftedEvery signal must include:
PlanVersionRefwhere applicable;Threshold semantics
entitlements-core; lifecycle signals are informational/action triggers only.Reference recipes
Provide code-declared recipes for:
Recipes must:
Composition boundaries
lifecycle-coremust not import provider SDKs.Diagnostics and ContractGraph
Acceptance criteria
Verification
pnpm --filter @croco/lifecycle-core testpnpm public-api:checkpnpm docs:api:checkNon-goals