Serdica · IPAL / ABACUS · requirements

Product Configurator Requirements

What the configurator must do to turn an insurer's product specification into a configuration that quotes, issues and prices correctly. The subject is a Bulstrad product in Serdica IPAL: configuration lives in four separate surfaces, two of them in a different database, and no tool moves a complete product between them. 52 requirements across nine areas, each with the check that proves it. Row counts are measured on PROD, 2026-09-02.

Reading this document

Requirement ids carry the area, not a sequence: SC scope · IN input · MD model · AB ABACUS · SY ABACUS→IPAL seed · PR IPAL product · IX INSIS integration · VF verification · GV governance. MUST is a release condition; SHOULD is defensible to skip with a stated reason. Every row names how it is checked, because a requirement nobody can fail is a wish.

Provenance tags mark every line of the product model, and are used throughout this page:

SPEC
The specification says so — the customer wrote it.
SYS
Derived from the system — a constraint, a key, a foreign key, a counted convention. Not a choice; the database already settled it.
DEC
A decision taken during configuration, and therefore something to confirm.

Sections marked + collapse the evidence behind a rule. Open them when you disagree with the rule — the counts are the argument.

SCScope & boundaries

The configurator produces files: a canonical product model, idempotent SQL per part, an acceptance script, a rollback script and a product document. It designs a configuration from a specification. It is not a migration tool, not a data-fix tool, and not an authority on whether the product should exist.

IdLevelRequirementVerified by
SC-1MUSTNever execute DDL or DML against any environment — not DEV, not inside a block that rolls back. Auditing, triggers and redo capture the attempt regardless.No write call in the transcript
SC-2MUSTNever alter a core table or column without explicit permission. The usual trigger is a product code longer than CFG_POLICY_NO_SEQ.PRODUCT_CODE VARCHAR2(4) — stop and offer the four-digit alternative first.No ALTER in emitted SQL
SC-3MUSTPropose the parts and ask which are in scope before writing anything. Group A (IPAL product), B (ABACUS tariff) and C (INSIS integration) are separately commissionable.Scope confirmed in writing
SC-4MUSTStop and ask when the specification is contradictory, silent, or undecidable from the data. A wrong guess about coverage scope, currency or clause mapping is business-visible.Open questions list is non-empty or explicitly empty
SC-5SHOULDReport a defect found in existing configuration rather than reproducing it. Discovering that a live product is wrong is a valid outcome of the work.Findings section

01The four surfaces a product occupies

A product is not one configuration. It is four, in two databases, with no foreign key between them — so nothing enforces consistency and nothing dictates the order of work. Two of the four have no maintenance screen at all.

Group A · IPAL DB

SRD_IPROD

The product

Catalogue, covers, risks and events, limits and deductibles, loadings, pricing factors, the screen, packages, annex types, texts. Maintained through the recommendation-engine UI.

Group B · IPAL DB

SRD_ANLT

The ABACUS tariff

Versions, covers, LD list, factors, rate files, deployed rulesets. The engine reads only DEPLOYED; an OPEN version is untestable, not safe.

Group C · IPAL DB

SRD_INTEGR

Rules and the INSIS seam

Field validations, the CFG_MAPPING_* map, and the ABC_* INSIS→ABACUS proxy — 7 packages, 14 tables, every entry point typed policy@insis%ROWTYPE. No UI — SQL only. 43 product codes hardcoded in its PL/SQL; zero in SRD_IPROD.

Group C · INSIS DB

ABC_ACCESS

INSIS-side ABACUS

36 CFG_ABC_* tables on PROD, 32 on TEST. Fires on the IPAL transfer as well as in INSIS Forms — the surface most often forgotten.

Why the fourth surface is not optionalThe IPAL transfer runs INSIS-side ABACUS checks, and one of them writestraced PROD

IPAL does not write a finished policy into INSIS. It writes an application and asks INSIS to convert it:

  • TR_POLICY:685 — ins_bof.pol(…), commented "transfer policy as an application"; the row lands at policy_state = -2
  • TR_POLICY:709 — GEN_APPL_PKG.CONVERT@insis(…)
  • INSIS.USEREXIT_GEN_APPL.Convert:3693 → abc_access.pr_abc.ConvertAppl(…); a false return rejects the conversion
  • PR_ABC.ConvertApplabc_lib.CommonPolicyValidation(…, 'CONVERT') unconditionally, then a per-LOB branch

USEREXIT:518/578 call the same package on both premium stages, so the surface is live for IPAL-originated policies at three points. CFG_ABC_FLD_VALIDATION by stage: BEFOREPREM 797 rows / 66 products · AFTERPREM 211 / 45 · CONVERT 60 / 16. The convert rows are underwriting-authority gates — reinsurance retention, minimum premium, head-office approval, back-dating.

TR_POLICY:732–738 sets l_st := TRUE on a failed convert for every product except 4710, so a rejected non-motor policy is reported as transferred.

Neither direction is a generatorWhy the model has to be authored, not derived from an existing surfacemeasured 2215

Product 2215 on PROD: 49 factors in PR_PRICING_FACTORS, 29 of them in PPA_FACTORS, and 3 appearing anywhere in the product's rate files. Even for a factor that appears, the grid carries only the values that differentiate the rate — so a rate file is a lower bound on the value set, never the set.

ppaSync carries the skeleton and no rates; it is absent from the bulstrad-prod and bulstrad-staging branches, and several of its defaults are wrong (taxRule='SUM' where every live product uses MULT). TRANSFER_PRODUCTS.CreateProduct — the system's own definition of a product, 91 tables in dependency order — touches neither SRD_ANLT nor ABC_ACCESS. A product moved by trProduct therefore arrives without its tariff.

INThe input contract

A specification is normally a set of files, or a directory of them — a tariff PDF, a cover workbook, a screen mock-up, an email settling one clause, a later revision of one sheet. Each describes a different part or a different aspect, they arrive at different times, and together they will still not contain everything. Treating them as one document is the first way this goes wrong; the second is treating them as independent.

The configurator's first job is to build one reading of the set, say which file is authoritative for which part, and name precisely what no file answers — in a form the author can answer.

IdLevelRequirementVerified by
IN-1MUSTAccept a set of files or a directory. Inventory it first: one line per file — name, date, which parts of the product it speaks to, and whether it is a source or a revision of another.Source inventory at the head of the model
IN-1aMUSTAssign one authoritative file per part. Where two files cover the same part, the later one wins only if it says so; otherwise it is a conflict, not a revision.Authority column in the source inventory
IN-1bMUSTReconcile across files rather than within each. A cover priced in the tariff and absent from the cover workbook is a finding, not an oversight to fix silently — and so is the reverse.Cross-document reconciliation table
IN-1cMUSTRestate the merged specification in its own terms before proposing anything, and name every place the set is silent.Restatement reviewed by the author
IN-2MUSTRead a rate as the document writes it and convert once, explicitly. 0.08 % of sum insured is 0.0008 in a rate file; getting this wrong is a factor of 100.Rate-file spot check against the tariff
IN-3MUSTTreat every risk the specification names as a cover to configure, including those it does not price.Cover count = risk count in the model
IN-4SHOULDRecord the source document, its date and its version alongside the model, and cite the clause for any value that a reader would otherwise have to trust.Model header
IN-5MUSTImplement a specification as written even when it appears wrong — a double-counted loading, a discount the spec calls manual — and raise the concern as a numbered question. Changing a price without a trace is worse than an odd price.Open questions list

MDThe canonical model

The same facts have to be stated in four places. Authored four times, they drift, and the drift is invisible until a premium comes out wrong. So the model is written first and once, and every emitted file declares which section of it it projects.

IdLevelRequirementVerified by
MD-1MUSTWrite one model file covering the whole product before emitting any SQL. Every generated file names the model section it projects.File headers
MD-2MUSTTag every line with its provenance — SPEC SYS DEC, as defined above. An untagged line is an unreviewable line.No unmarked line
MD-3MUSTCollect every DEC line into a numbered open-questions list. A model with no DEC lines means the gaps were filled silently — that is the failure this practice exists to prevent.Question count > 0
MD-4MUSTFreeze the shared vocabulary in the model: cover codes, factor codes, factor names, and the ANLT_VALUE strings a rate grid must match character for character.Vocabulary section is complete before part files
MD-5SHOULDRecord a genuine asymmetry between surfaces as a deliberate difference rather than harmonising it in one file and forgetting the other.Asymmetry list
MD-6MUSTChange the model first and regenerate what depends on it; never patch a projection alone.Counts in the acceptance script derive from the model

"One character off and the grid resolves on (Other) — a different premium, with no message."

— on why the vocabulary is frozen before either surface is written

A rate grid's row and column headers carry the factor name, not the code, and its cells match PR_PRICING_FACTOR_VALUES.ANLT_VALUE as literal strings. On a new product the cheapest way to remove the whole class of mismatch is to set PRICING_FACTOR_NAME = PRICING_FACTOR_CODE, so code, header token and request key are one string with nothing left to keep in sync.

02The procedure

marks a gate — work does not proceed past it, and nothing is reported complete until every gate has been passed.

  1. Inventory the source set, then restate itOne line per file: what it speaks to, which part it is authoritative for. Reconcile across files. Name what the set is silent about. No configuration decisions yet.
  2. Inventory the target environmentRead-only. What exists already, in which of the four surfaces, and which environment the work targets. Feature-gated products go to QA; general work to TEST.
  3. Propose the parts and askGroups A, B and C, itemised. Scope is the customer's decision, not an inference from the spec.
  4. Write the canonical modelSPEC / SYS / DEC on every line. Vocabulary frozen. Open questions numbered.
  5. Check the model, not the SQLCover set, factor set, value sets, the tariff's own arithmetic. Errors are cheap here and expensive after four projections.
  6. Emit the tariff — ABACUS firstRates are the only never-derivable artefact and carry the longest lead time. They can be exercised before a single IPAL row exists.
  7. Emit the product — IPALCatalogue, covers, risks and events, limits, loadings, factors, screen, packages, annexes, texts, documents, access.
  8. Emit the integration — only if group C is in scopeMapping, validations, the INSIS core rows, the ABC request map. Expect some of the 15 product-aware SRD_INTEGR packages to need a dev change, not a config row.
  9. Write the acceptance and rollback scriptsCompleteness per surface, cross-layer agreement, and a rollback that removes exactly what was added.
  10. Prove a premium end to endA quote that renders and reconciles against the tariff by hand. A configuration that has never produced a number is not finished.
  11. Write the product documentWhat was configured, what was decided, what remains open, and how to undo it.

"Both reported five packages. A check that agrees with itself cannot detect an absent step."

— why step 10 is a gate and not advice

A product was handed over as complete with its pricing reconciled to the cent, and it could not produce a quote: the packaging layer had never been wired, and the check that should have caught it measured the work against the plan that produced it. Verification that derives from the model can only prove internal consistency. Only the running system can prove the product works.

03The estate is evidence, not a template

The configuration is a new design answering this specification. The 57 live products are the best available evidence about what the schema allows, what the code reads and what vocabulary is already in use — and they are also, sometimes, wrong, dated or half-finished. Look before choosing; do not let what you find make the choice.

How much authority an observation carries
What you observedAuthority
The schema says so — type, length, NOT NULL, CHECK, FKBinds. COVER_CODE VARCHAR2(15) is a limit, not a habit
The backend or the UI branches on the valueBinds functionally — confirm in the source, not from the row count
A naming grammar or house styleFollow it unless you have a reason; say so in the model when you deviate
One column tracking another in 100 % of rowsA correlation, probably a rule — verify before relying on it or breaking it
A split across live productsWhat others chose, not what yours should be — decide from the spec and tag it DEC
One or two rowsDirt or a defect — not a precedent, and often worth reporting
Naming and value rulesCover codes, limits, factors, texts — the counted conventions and the column limits behind themPROD · 57 products

Cover codes. 692 of 692 live codes match ^[A-Z0-9_]+$; VARCHAR2(15) NOT NULL, lengths 2–15. Uppercase English — a whole word when it fits in 15 characters (THEFT, FLOOD, LIABILITY, EARTHQUAKE), an abbreviation only when it does not (BI_TERRORISM).

Limits and deductibles follow a grammar that carries meaning: DEDUCTIBLE* percent · DEDUCTIBLEV* absolute value · LIMIT_AG_* aggregate · LIMIT_EV_* per event · LIMIT_PE_* / LIMIT_KG_* per person, per kilogram · FRANCH, PML, LPD_*, LBI_*. An aggregate legal-expenses limit is LIMIT_AG_LEGEXP.

Message keys are product-firstP7008_PF_IV_HOME, not PF_7008_IV_HOME — so one LIKE 'P7008\_%' shows the product's whole vocabulary and one statement removes it. The tables carry no PRODUCT_CODE, so a generic key lets a new product silently inherit another's wording.

ColumnLive shapeConsequence
SR_MESSAGES.MSGLatin-only on 12 858 / 14 612 (88 %)The parent row carries the English / technical wording
SR_MESSAGES_LNG.LANGUAGEBG on 14 512 / 14 516One BG row per key. An EN row here has never been written
SR_MESSAGES.MSG_TYPEMESSAGE 13 759 · ERROR 829 · LABEL 22Labels are MESSAGE. LABEL is not the convention despite its name
SR_MESSAGES.MSG_PURPOSENULL on 98.8 %Names the owning subsystem (BOT, BETH) — leave NULL
PR_PRICING_FACTORS.SALE_STAGEPOL 1 977 / 1 977One row per factor. QT exists only on DEV
PR_PRICING_FACTORS.DATATYPELIST 1 038 · NUMBER 259 · IV_COV 245 · …Drives the UI field generator. STRING has 2 rows — use TEXT
PR_PRICING_FACTORS.VALUE_SOURCEPOV 84 %The rest are C# PascalCase EF paths — pc.SrObjects.ObjCar.EngineType
PR_BASIC_LD.SEP_ACCOUNTtracks LD_TYPE 1 465 / 1 465LDN, TAXY — derive it
PR_BASIC_LD.LD_SIGN+1 1 000 · −1 465The sign, not the type, separates loading from discount
PR_BASIC_PRODUCTS.LOBten free-text spellingsNo convention at all — one value has a Cyrillic Е and is misspelled
Object types, and the animals question37 live types; which one a pet product uses, and what does not exist yet430 mapping rows

OBJECT_CODE VARCHAR2(20). 37 values live in SRD_CUST.SR_OBJECTS.OBJECT_TYPE, bound to INSIS by SRD_INTEGR.CFG_MAPPING_OBJECT_TYPES. The large ones: CAR 466 908, PROP 49 084, HOME 42 904, CONTENT 39 747, CARGO 18 116, GRPPA 8 304.

  • ANIMAL — farm and productive animals: cow, horse, sheep, goat, pig, poultry. Live on product 3510 as INSURED_OBJECT with OBJECT_NUM ← NUM_INS_OBJ.
  • PET — companion animals: cat, dog and the like. Does not exist yet — absent from both the 37 live types and the mapping table. A pet product must create it, and if group C is in scope it also needs an INSIS object model and an insr_type.
Environments differ, and DEV differs mostA shape observed in one environment is an anecdote — count it in all threeDEV / TEST / PROD
ObjectDEVTESTPROD
PR_PRICING_FACTORS.UI_REQUIREDexists, NOT NULLexistscolumn absent
SALE_STAGE = 'QT'23 products / 254 rows00
PR_CONSISTENCY_CHECKStable absent52 rows
INSIS + ABC_ACCESSabsentpresentpresent
The transfer chainonly TR_POLICYpresentpresent

DEV is where abandoned ideas (QT) and not-yet-arrived ones (UI_REQUIRED) both live. Product 8000 / ДЗО work and anything touching SRD_HLT goes to QA; general configuration goes to TEST.

ABThe tariff — ABACUS

IdLevelRequirementVerified by
AB-1MUSTEmit one rate file per rated cover, with rates as fractions. Cells are <FACTOR> in (value) bands with a final <FACTOR> (Other); rows and columns carry factor names.Hand-computed premium for one risk
AB-2MUSTConfigure a cover the spec does not price with rate 0 rather than omitting it, in both PR_BASIC_COVERS and PPA_PRODUCT_COVERS.Cover counts agree across surfaces
AB-3MUSTLeave SELECTED='Y' and CHANGEABLE='Y' so an underwriter can price a zero-rated cover at policy or application time.Manual premium accepted in the UI
AB-4MUSTState the version's EFFECTIVE_DATE and TEMPLATE_CODE explicitly. Version selection is ORDER BY version_id DESC among DEPLOYED rows — the highest id wins, not the latest date.Version query returns the intended row
AB-5MUSTState the composition rule per product: Sum or Multiple, and the order. The order is not cosmetic.Worked example in the product document
AB-6SHOULDExercise the tariff on its own — before a single IPAL row exists — and reconcile one premium against the tariff document by hand.Reconciliation table

1300 × 1.05 × 1.30 × 0.90 − (1300 × 0.10) = 1467  ·  1300 × 0.90 × 1.05 × 1.30 × 0.90 = 1437

— the same base premium, the same four factors, two orders of application

Mixing a Sum-composed discount with Multiple-composed ones puts 30 EUR between two defensible readings of one tariff. This is why AB-5 exists: "which discounts apply" is never the whole question — in what order, and composed how is the rest of it, and it is a per-product decision that must be written down.

SYSeeding IPAL from ABACUS

Once the tariff exists, part of the IPAL product can be written from it rather than typed again. Measured across the 63 products ABACUS knows on PROD, that part is real but narrow: it covers three of the twelve parts and roughly one configuration row in seven. It is therefore specified as a seed — a one-time write at creation, not a standing synchronisation.

What the seed can carry, counted on PROD 2026-09-02 over the 63 products present in PPA_PRODUCTS
ObjectIn IPALABACUS knowsCoverageIPAL-onlyABACUS-only
Covers54753898.4 %9290
Loadings & taxes41538091.6 %35181
Pricing factors1 44363844.2 %805210
IdLevelRequirementVerified by
SY-1MUSTRun once, at creation, and emit SQL like every other part. It is a seed, not a running sync — re-running it later would overwrite decisions IPAL is the only owner of.Seed file carries the model section and a generation timestamp
SY-2MUSTSeed only what ABACUS actually owns: cover codes and their OBJECT_CODE (537 of 538 shared covers agree), the loading/tax list with LD_CODE, LD_TYPE, LD_SIGN, and the factor skeleton (code, name, datatype).Column-by-column list in the seed file header
SY-3MUSTNever invent COVER_TYPE. ABACUS has no equivalent of COV/OPT, and mandatory-versus-optional is a commercial decision — every seeded cover arrives tagged DEC.No seeded cover reaches SQL without a confirmed COVER_TYPE
SY-4MUSTFilter the ABACUS-only rows rather than importing them: 290 covers and 210 factors exist in ABACUS and not in IPAL. Most are engine-internal or per-clause splits; each one is a question, not a row.Rejected-rows list in the seed report
SY-5MUSTReport the seed's own coverage per product before it is trusted. It ranges from 78 % of the factor set on 2200 to 11 % on 4800 — the average tells you nothing about the product in front of you.Per-product coverage line in the seed report
SY-6MUSTState plainly, in the same report, that the seed writes none of the nine remaining parts, and give their live row counts so the remaining work is visible.The "not seeded" table below appears in every seed report
What the seed does not writeNine parts with no ABACUS counterpart — with the live row counts they carry across the same 63 products≈ 7 870 rows
PartRowsWhy ABACUS cannot supply it
PR_PRICING_FACTOR_VALUES2 639ABACUS stores the values that differentiate a rate, never the value set an operator picks from
PR_BASIC_COVER_DEF2 278Limits and deductibles are policy terms; the engine sees only their effect on price
LB_OFFER_COVERS1 541Packaging is a commercial construct with no rating meaning
CFG_FLD_VALIDATION530Field rules belong to the integration layer, not to pricing
PR_BASIC_COVER_RISKS320Perils are the wording of the cover, invisible to a rate
LB_OFFERS289See packaging — and this is the layer whose absence let a product reconcile to the cent and fail to quote
PR_BASIC_COVER_EVENTS216Claim events, same reason as perils
PR_ANNEX_TYPES37Endorsement types are a lifecycle concern
PR_BASIC_PRODUCT_DOCUMENTS20Print configuration

Plus, with no row count because they are not per-product tables: every SR_MESSAGES label and translation, CFG_POLICY_NO_SEQ, the roles and routes that make the product reachable, and the whole screen layer — UI_GROUP, UI_ORDER, POLICY_TABLE, VALUE_SOURCE, DEFAULT_VALUE. A factor seeded from ABACUS arrives with a code, a name and a datatype, and nothing that puts it on a screen or tells the backend where to read it.

Column by columnWhat arrives filled, what arrives empty, and what has to be decided3 tables
TargetSeeded from ABACUSLeft empty or decided
PR_BASIC_PRODUCTSBASIC_PRODUCT_CODE, LOBGENERIC_NAME, VALID_FROM/VALID_TO
PR_BASIC_COVERSCOVER_CODE, OBJECT_CODECOVER_TYPE DEC, LIABILITY, COVER_ORDER, validity
PR_BASIC_LDLD_CODE, LD_TYPE, LD_SIGNSEP_ACCOUNT (derive from LD_TYPE), NCB, FINST, REFUNDABLE, cover-vs-product level
PR_PRICING_FACTORSPRICING_FACTOR_CODE, PRICING_FACTOR_NAME, DATATYPE, QT_REQUIREDPRICING_TYPE, POLICY_TABLE, VALUE_SOURCE, UI_FLAG, UI_ORDER, UI_GROUP, DEFAULT_VALUE, COVER_CODE, OBJECT_CODE, SALE_STAGE

CALC_ORDER on the ABACUS side looks like COVER_ORDER and is not: one is the sequence the engine prices in, the other is the sequence an operator reads. Seeding one from the other produces a screen ordered by arithmetic.

98 % of the covers, 44 % of the factors, and none of the nine parts that make the product reachable.

— why this is specified as a seed and not as a synchronisation

The word matters. A sync implies the two sides can be kept in agreement, which invites a second run later — and a second run would overwrite COVER_TYPE, UI_GROUP and every other column IPAL alone owns. A seed is a one-time head start that removes typing, not judgement: it fills the skeleton, tags what it could not decide, and leaves the twelve-part completeness check exactly where it was.

PRThe product — IPAL

IdLevelRequirementVerified by
PR-1MUSTConfigure all twelve parts a reachable product needs, not only those the spec mentions: catalogue, covers, risks and events, limits, loadings, factors and values, screen, packages, annex types, texts, print documents, roles and routing.Completeness script, one count per surface
PR-2MUSTRead TRANSFER_PRODUCTS.CreateProduct as the maintained definition of "a product" — 91 tables in dependency order — rather than any prose list, this one included.Part list reconciled against the package
PR-3MUSTAllocate every globally unique key deliberately: product code, tariff file name, CFG_ID, MSG_ID, question id, print REP_ID. They collide across products.Uniqueness check per key space
PR-4MUSTCreate a carrying SR_MESSAGES row for every label — MSG_ID is a hard FK, and the translation cache is built by enumerating the parent table. A key with no parent never reaches the UI.Orphan-key query returns zero
PR-5MUSTSupply sequence values explicitly. There are no triggers and no identity columns on these tables.SQL review
PR-6SHOULDReuse an existing shared code rather than minting a near-duplicate; a new code in a shared register needs a stated reason.Vocabulary section of the model

IXINSIS integration — only when commissioned

IdLevelRequirementVerified by
IX-1MUSTConfirm the product code can exist in INSIS before promising a transfer. HT_INSR_TYPE holds only the bands 11 · 22 · 33 · 34 · 35 · 36 · 38 · 47 · 48 · 59, and CFG_MAPPING_PRODUCT_CODES has exactly one row — so by default the IPAL code is the INSIS insr_type.Band check against HT_INSR_TYPE
IX-1aMUSTNot configure SRD_INTEGR.ABC_* for an IPAL-only product. It is the INSIS→ABACUS proxy (7 packages, 14 tables, every entry point typed policy@insis%ROWTYPE); IPAL calls the engine directly from the backend. It matters only when the product must also be priced from the INSIS side.The request map is empty for a group A+B product, deliberately
IX-2MUSTConfigure ABC_ACCESS.CFG_ABC_FLD_VALIDATION and CFG_ABC_OFFICE_VALIDATION when group C is in scope. They run on the IPAL transfer, not only in INSIS Forms.Convert-stage rules listed in the model
IX-3MUSTSay plainly which of the 15 product-aware SRD_INTEGR packages need a new branch. That is a dev change on the Ablera process, not a configuration row.Dev-change list
IX-4MUSTRaise a Change Request for any INSIS code or user-exit change. Manual data corrections on specific policies do not need one; code does.CR raised
IX-5SHOULDVerify the transfer end to end rather than trusting its return value — a failed conversion is reported as success for every product except 4710.INSIS policy_state after transfer

VFVerification & deliverables

IdLevelRequirementVerified by
VF-1MUSTShip an acceptance script with four parts: completeness per surface, deliberate omissions, cross-layer agreement, and the manual test.Script runs read-only and reports counts
VF-2MUSTDerive expected counts from the model, so a changed decision surfaces as a failing count rather than a silent inconsistency.Counts traceable to model sections
VF-3MUSTShip a rollback script that removes exactly what was added, in reverse dependency order.Rollback reviewed against the emitted SQL
VF-4MUSTProve one premium in the running system and reconcile it by hand against the tariff. Internal agreement is not proof.Screenshot or quote id plus the arithmetic
VF-5MUSTState every deliberate omission explicitly, with its reason, rather than letting a zero count read as an oversight.Omissions section of the acceptance script
VF-6SHOULDPublish a product document: what was configured, what was decided, what remains open, how to undo it.Document exists and is indexed

GVThe vocabulary it must speak

Product models and product documents use the insurance terms below, and the configurator maps each one onto its column rather than inventing a synonym. Getting the word right is how a business reader and a database reader stay in the same conversation.

TermMeansColumn
Base premiumThe rating-table output, before anything is applied. One row per cover.PREM_TYPE='BASEPREM'
Written premiumBase premium after loadings and discounts.PREM_TYPE='WRITTENPREM'
Loading / discountAn uplift or reduction. The sign distinguishes them.LD_TYPE='LD', LD_SIGN ±1
Tax / feeKept separately from premium; each is refundable or not, and first-instalment or spread.LD_TYPE='TAX'
Insured valueThe sum insured. Its currency is the policy currency.POL_OBJECT_VALUES 'IV'
Short rateA non-proportional rate for sub-annual periods: raises short premiums, cuts early refunds.SHORT_AMNT
Earned / unearned premiumThe elapsed and remaining parts of the period. UPR = GWP − EP.computed
Write-offUnearned premium. Base: annual premium less non-refundable items.
RefundUnearned paid premium. Base: instalments actually paid, less non-refundable items. A different number from the write-off.
AnnexAn endorsement. A premium change appends a negative row; it never edits the old one.POL_ANNEXES
Deductible / limitPer cover; percent or absolute, aggregate or per event.PR_BASIC_COVER_DEF
IdLevelRequirementVerified by
GV-1MUSTUse these terms in the model, the product document and any customer-facing reply, and name the column beside the term whenever both readings matter.Document review
GV-2MUSTNever call IPAL or INSIS "the core" — both are policy administration systems. Name them.Document review
GV-3MUSTShow the currency code with every monetary value. Amounts are stored in main units, and EUR is the default — older policies may be BGN or USD.Grep for bare numerics in the product document
GV-4SHOULDRecord a newly measured convention, or a defect found in an existing product, where the next run will read it — not only in the deliverable.Knowledge or memory entry

"The document is a design intent, not a description of the running system."

— on the premium specification the vocabulary comes from

The source it is drawn from carries seventeen recorded defects, two of which contradict PROD outright: it specifies CHANGEABLE='N' for base premium, where all 7 035 157 rows ever written carry 'Y'; and its field mapping lists 18 of the 22 live columns, omitting REFUNDABLE and MANUALLY_CORRECTED — the two the manual-premium rule depends on. Take the vocabulary from it; check the columns against the database.

04Traps that have cost a release

A permitted shape is not a used shapeConstraints answer "allowed"; GROUP BY answers "done"recurring

PR_BASIC_LD.LD_TYPE permits FEE; across 1 465 rows it is never used. SALE_STAGE permits QT; PROD and TEST hold none. MSG_TYPE permits LABEL; 22 rows carry it. Being the first product to use a permitted value is allowed — doing it without noticing is the failure.

Verification that agrees with itselfChecking the build against the plan that produced it proves nothinggate 10

Counts derived from the model detect drift between projections. They cannot detect a step that was never in the model. Only a rendered quote reconciled by hand against the tariff closes that gap, which is why it is a gate.

Assuming the surfaces are orderedThere is no FK between SRD_ANLT and SRD_IPRODstructural

The two are coupled by code and by name, not by constraint, so nothing in the database says which is written first. What must precede both is the model's frozen vocabulary. After that, default to ABACUS first — rates are the only never-derivable artefact, they carry the longest lead time, and PR_BASIC_LD derives from the ABACUS LD list rather than the reverse.

Deploying the tariff version to "finish"The engine reads only DEPLOYED — deploy is the gate, not the formalityABACUS

genRuleTable requires stage DONE or CONFIRMED plus an EFFECTIVE_DATE, then writes RATING_TABLE_FILES per version. A tariff edited but not deployed changes nothing; a tariff deployed to the wrong version changes the wrong product. One file set can feed N deployments.

Reading a tariff percentage literally0.08 % is 0.0008 — the error is a factor of 100AB-2

Rate files hold fractions. Product 2215 carries 0.007 and 0.028 at BP_RATE_DIM='P'. A percentage copied from a tariff document without conversion produces a premium a hundred times too large, and it will still render.

05Out of scope

Named so that nobody assumes otherwise: executing configuration against a database; migrating a product between environments (trProduct carries neither the tariff nor the INSIS-side ABACUS configuration — budget both separately); INSIS code and user-exit changes, which need a Change Request; IPAL backend and UI changes, which are the Ablera dev process; pricing policy — the configurator implements a tariff, it does not judge one; and the commercial decision of whether the product should be built.