Stage S4 — Offer
Purpose
The product exists and prices; now decide how it is sold: this stage creates the offer cuts over the possible pricing factors, with the covers each offer carries — the packages an operator (or a partner channel) actually picks from, which covers are mandatory/recommended/optional in each, the preset limits, and the rules between covers. Without it the platform answers "no offers could be found" — a correctly priced product that cannot produce a quote F: [LB offers and cover rules].
Inputs → Outputs
In: the S3 catalogue (covers, definitions, factors) + the specification's packaging wishes (segments, variants, "standard/extended/premium" cuts). Out: offers with cover extents (M/R/O) and preset values; dependency/conflict/limit-restriction rules; the offer→template pricing links; the stage's script set.
What runs this stage
| Agents | configuration.offer.stage |
| Isolated sub-agents | configuration.verifier |
| Memory domain it owns | configuration/offer — packaging shapes, rule kinds, available versus selected (Agents Memory) |
| Skills it runs | ipal configure (offers, packages, rules — the write path) · offer test (the proof) (Agents Memory and Skills) |
| Its branch of the graph | Configuration Module § 0 — the module's agent tree, its memory branch and its skills · the component list is Components — Configuration |
Every stage also uses the module's shared profiles — configuration.root (the only one that reaches the human), configuration.verifier (isolated, no author context) and configuration.deployer — and the platform's write_executor and write_auditor, which are what actually touch a target (Gating).
The protocol here
- Plan: the offer matrix — offers × covers with extents and preset limits — plus the rules (X requires Y; A conflicts with B; theft ≤ 10 % of fire) and, per offer, which rating template prices it; confirmed with the human (this is business shaping, the human usually has opinions here).
- Apply: LB offers, offer covers, cover values; dependency and conflict rules; limit restrictions; the offer pricing rule naming the template F: [LB offers and cover rules].
- Test — the offer skill: resolve offers through the real offer path per object/segment; assert each package carries exactly the specified covers/extents/limits; construct violating selections and assert the rules fire; assert selection semantics — available is not selected (a rating response listing all priced covers must not silently select them all [F: the PC 9951 run]).
- Iterate: the human reviews the cuts as an operator would see them; adjust until satisfied.
Facts to hold F
- Offer resolution runs before rating at quote time — offer gaps mask rating correctness; the rating engine knows nothing about offers, the single bridge is the template code.
- A cover dependency needs one row per admissible pair, and the dependent reference carries driver + value path — a bare code stores happily and filters nothing; a missing pair is an empty mandatory dropdown blocking the quote.
- Relative limits are restriction rules (EXC/EQ/FALL relationships), not typed numbers.
Real material — what live cases asked of this stage
Eight configuration cases were walked against this design (Configuration Module § 8 carries each case in full). What each one demanded here:
CS-1 · 9951 «Каско Максимум» replayed through v2 — The PC agent built 9951 on Ablera dev from a 13-sheet template (Продукт · Тарифни групи · Клаузи · Покрития · Зависимости · Оферти · Правила за премия · ЗС/лимити · Подписвачески въпросник 91 rows · Зависимости между въпроси 65 rows · Такси · Ref) and a 10-page tariff PDF (raздели I–VIII).
Five offers on segment ALL against the reused LB_OBJECT_NA for CAR; extents from Оферти (MINI: CM1 only; FULL: CM4 + assist Д + mech + seats + replace); dependency rows one per admissible pair (CM_ACCIDENT requires CM_FIRE_NAT …); the clause mutual exclusion is a conflict — and the PC extract already notes LBRR_COVER_CONFLICTS has no group column, so „exactly one clause" is N flat rows. Offer skill: available ≠ selected. [ok] with the schema caveat (below).
CS-4 · HelpDesk 00098747 — 2214/2215 promo „65 години Булстрад": pay 60 months, get 65 — Home products 2214/2215: for the campaign, term 65 months, premium for 60; everything else unchanged.
No new offer; but if Bulstrad had wanted „Промо 65" as a selectable package it would be LB_OFFERS with LB_OFFER_PRICING_RULE naming a promo template. [ok].
CS-5 · Product 8000 „Здравна грижа" — packages × levels × options, cover modes, a Camunda process, CG-9 — Group health, EUR, QA only (10.239.82.106), 10 UI covers + 52 level-variant child rows (IP_O/IP_L/IP_E), consumption modes PRV/REIM per cover (PREVENTION and EXTRA_CARE PRV-only), tariff per member × package × level × option with ordered corrections (sector, group size, age band, −5 % commercial), Профилактика individually rated (no rate), Критични заболявания only above 150 persons, claims-side ABACUS templates SRVPRICE# and CLMIND#, BPMN in Core.Plugin.Bulstrad, HealthBasicProductId=8000 hardcoded.
Packages = offers with M/R/O; levels as preset LIMIT values per offer; PRV/REIM as … nothing in LB_* — it is MEMBER_CARDS.COV_n_PRV/REIM runtime data. [gap P] again.
Challenges
- P Which layer owns a "visible only to customer group X" wish — offer segmentation vs role-gated routes (Serdica) — decided by one question, not per case (D138, 04.09.2026): who is X — the insured or the seller? The estate keeps the two apart F:
SRD_SYS.Routes.AllowedRolesand product-gated role ids such asUR_3607/UR_4800gate the operator who sees the product ([IPAL schema § UI menu / role-gate); offer segments (ALLin the PC extract) classify the insured object; a pricing factor'sATTR3is a per-value role gate]. So: X describes the insured (a fleet, a pensioner, a cargo class) → S4 offer segment; X describes who sells or services (an agency, a partner, a back-office team) → S5Routes.AllowedRoles, with a newLT_USER_ROLESrow when no existing role fits;ATTR3is reserved for hiding a factor value from a role (S3) and never used for product visibility. S1 classifies the wish accordingly inrequirements[](Stage Normalization); only a wish naming both goes to the human. - P Rule-combination testing strategy: assert the specified rules, sample the violation space — define the sampling with the first eval set.