diff --git a/workplans/ADAPTIVE-WP-0010-plan-derived-guardrail-ceilings.md b/workplans/ADAPTIVE-WP-0010-plan-derived-guardrail-ceilings.md new file mode 100644 index 0000000..c96785b --- /dev/null +++ b/workplans/ADAPTIVE-WP-0010-plan-derived-guardrail-ceilings.md @@ -0,0 +1,138 @@ +--- +id: ADAPTIVE-WP-0010 +type: workplan +title: "Plan-derived guardrail spend ceilings" +domain: financials +repo: adaptive-pricing +status: proposed +owner: codex +topic_slug: helix-forge +created: "2026-08-18" +updated: "2026-08-18" +--- + +# Plan-derived guardrail spend ceilings + +Give `tenant-engine`'s guardrail resolver a commercial feed, so a tenant's +monthly spend ceiling derives from the plan it holds rather than from a +headcount band that nobody signed off on. + +Offered by `tenant-engine` on 2026-08-17 alongside the TEN-WP-0010 grouping +change (`tenant-engine/docs/tenant-guardrail-policy.md`, TEN-WP-0006). The +precedence layer already exists in their resolver — a plan-derived limit +outranks a grouping default — and it has no feed today. + +## Position + +**The problem is ownership, not mechanism.** Ceilings currently resolve from +`tenant::`'s middle segment. Reclassifying a tenant from `small` +to `enterprise` moves its ceiling from EUR 250 to EUR 20,000. That is a +commercial fact wearing operational clothing: `tenant-engine` states plainly +that every non-trial value is a conservative opener they chose so no grouping +started unbounded, and that nobody has approved them commercially. Only +`trial = 0` is canon, from ADR-0013. + +This is the same shape the tenancy framework was written to stop — a +customer-affecting commercial commitment resolved by an operational default +with no recorded owner. `adaptive-pricing` owns plan terms, so this is ours to +feed. + +**A plan is a better basis than a band.** The grouping is a proxy for size; the +plan is the actual agreement the customer entered. Deriving a blast-radius limit +from what someone bought is more defensible than deriving it from what bracket +their headcount fell into at onboarding — particularly now that grouping is +mutable (TEN-WP-0010) and the identifier's middle segment is historical rather +than authoritative. + +**Two constraints, stated up front because they shape the design.** + +*A ceiling is a guardrail, not a price.* The moment a limit derives from plan +terms there is pressure to present it as an entitlement the customer purchased. +That is a different product with different obligations — an entitlement implies +we will serve up to it, a guardrail only says we will stop beyond it. The design +must keep them distinguishable, and the customer-facing wording must not +promise capacity. + +*A ceiling change is a commercial event.* It goes through the tier-terms +approval path rather than resolving silently, consistent with `SCOPE.md` on +customer-visible pricing changes and with the `ADAPTIVE-WP-0009` T04 gate. + +**Not yet agreed with `tenant-engine`.** They offered the conversation; we said +yes in principle and flagged it as new scope. Nothing here is committed until +T01 produces a shape both repos accept. + +## Establish The Interface Contract With tenant-engine + +```task +id: ADAPTIVE-WP-0010-T01 +status: todo +priority: high +``` + +Agree the shape of the feed jointly with `tenant-engine`: what +`adaptive-pricing` publishes, what their resolver consumes, and what happens on +stale or missing input. + +Open questions to settle, not to assume: +- Is the ceiling a field on the pricing model, or a separate derivation from it? + A tier's ceiling is not obviously one of its charge components. +- What resolves for a tenant whose plan carries no ceiling — the grouping + default, or a refusal? Falling back silently reintroduces the problem. +- Which side holds the number when they disagree? `ADAPTIVE-WP-0009`'s answer + for assurance claims was that the tier definition is authoritative and other + records derive from it; the same logic likely applies, but say so explicitly. +- Does a plan change mid-period move the ceiling immediately or at renewal? + This is a commercial answer, not a technical one. + +Record the outcome as a decision, since it binds two repos. + +## Extend The Pricing Schema With Ceiling Terms + +```task +id: ADAPTIVE-WP-0010-T02 +status: wait +priority: medium +``` + +Blocked on T01. + +Add the agreed representation to the canonical schema. Follow the +`assurance_claims` precedent from `ADAPTIVE-WP-0009-T02`: optional, typed, +defaulted, so every existing model stays valid and silent tiers keep resolving +from the grouping default until deliberately migrated. + +Keep the guardrail/entitlement distinction structural rather than a comment — +if the field is named or shaped like an allowance, it will be read as one. + +## Validate Ceiling Coherence + +```task +id: ADAPTIVE-WP-0010-T03 +status: wait +priority: medium +``` + +Blocked on T02. + +Boundary-engine rules, explainable in the existing style: +- A ceiling below the tier's own expected usage is incoherent — the tier would + stop the customer doing what they paid for. +- A ceiling must not be presented in customer-facing wording as capacity. +- A tier with usage-based components and no ceiling is a declared choice, not an + oversight; require it to be explicit. + +## Route Ceiling Changes Through Approval + +```task +id: ADAPTIVE-WP-0010-T04 +status: wait +priority: medium +``` + +Blocked on T02. + +Extend the `ADAPTIVE-WP-0009-T04` governance gate so a tier acquiring or +changing a ceiling raises a blocking approval requirement at tier definition, +carrying the prior and proposed values. Reuse the existing comparison +machinery rather than adding a second gate; as with assurance claims, it must +stay a definition-time review and not become a per-campaign one.