adaptive-pricing/workplans/ADAPTIVE-WP-0010-plan-derived-guardrail-ceilings.md
codex 01f49aa45d
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
fix(workplans): adopt ADR-007 derived identifiers for unregistered records
These workplans exist only in the retired local hub. Their random pre-ADR-007
identifiers are refused by C-06 as stale references, so they cannot be
registered. Deriving from the canonical record id takes no identity from
anything: central does not hold them and the old ids die with the cache.

Records central already holds were deliberately left untouched.

Refs CUST-WP-0068-T06

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2583210@bnt-lap001
Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
2026-08-25 20:06:58 +02:00

5.6 KiB

id type title domain repo status owner topic_slug created updated state_hub_workstream_id
ADAPTIVE-WP-0010 workplan Plan-derived guardrail spend ceilings financials adaptive-pricing proposed codex helix-forge 2026-08-18 2026-08-18 543e6398-d2cb-5105-977e-b90461adac3e

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:<grouping>:<name>'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

id: ADAPTIVE-WP-0010-T01
status: todo
priority: high
state_hub_task_id: "7533431c-a0de-5ac8-a811-14e4604ad651"

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

id: ADAPTIVE-WP-0010-T02
status: wait
priority: medium
state_hub_task_id: "7bd4dace-3505-5c68-977d-f80b30aebc77"

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

id: ADAPTIVE-WP-0010-T03
status: wait
priority: medium
state_hub_task_id: "46e49880-21ff-580f-a2ad-82c8f1401afc"

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

id: ADAPTIVE-WP-0010-T04
status: wait
priority: medium
state_hub_task_id: "a3eeffa6-57b0-5dc1-8b07-4b9b2a3d3534"

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.