Serdica · ABACUS (+ IPAL) · product design

Product Configurator — the product

Turning the authoring workspace into a deployed service: a web application that accepts a specification in whatever form it arrives, drives a provider-agnostic AI backend, and produces tariff and product configuration either as files or written straight into ABACUS. The design turns on one claim — ABACUS is the product, IPAL is an option — and on the observation that ABACUS's own version-and-deploy model is what makes writing to a live database safe. Below: the two deployment shapes, the run pipeline, the AI layer, the write path, the correction loop, the workspace UI, single sign-on against IPAL, and the decisions with the alternatives they beat.

00What is changing, and what is not

Today the configurator is a Claude Code workspace: a human opens a directory, a model reads the specification, and the deliverable is a set of files that somebody else executes. It works, and the reason it works is worth keeping — one canonical model, every emitted artefact a projection of it, and four refusals that stop the model from inventing facts or touching a database.

What changes is everything around that core: who runs it, how the input arrives, where the output lands, and what happens when the answer is nearly right. What does not change is the core itself. The model is still written first and everything else is still a projection of it. A correction edits the model and re-projects; it never edits emitted SQL.

The four refusals, carried into a product. Three survive intact; one is replaced by a mechanism.
TodayIn the productEnforced by
R1 · never execute
DDL or DML
Replaced. The service writes, but only into a new, undeployed ABACUS version, and only into an allow-listed set of tables. Nothing it writes is live until a human deploys. Write adapter with a table allow-list; deploy is a separate, role-gated action the service never takes on its own. § 05
R2 · never alter a core
table without permission
Kept. A product code that will not fit VARCHAR2(4) still stops the run and asks. The same allow-list. DDL is not in it at all.
R3 · never report complete
on a self-derived check
Kept and automated. The workspace could not verify because it had no right to run anything. The service can: it calls getRates itself and reconciles the result against the tariff. The verification gate. A run cannot reach Verified without a rendered premium that reconciles. § 03
R4 · never fill a gap
silently
Kept and promoted. A DEC line stops being a bullet in a markdown file and becomes a first-class object: an open question with an owner, an answer, and a timestamp. The model schema. A run carrying unanswered DEC items cannot be published. § 06

R1 is the whole risk of this project. Every other change is additive. Moving from „emits files“ to „writes to your database“ is the change that can lose someone money, and § 05 exists to argue that ABACUS's versioning makes it survivable. If that argument does not convince a reviewer, the correct outcome is to ship the file-emitting product first and the write path later — they are separable, and § 12 sequences them that way.

01Two shapes, one product

The workspace was built against a customer who runs both IPAL and ABACUS. That is one deployment, not the definition of the market. ABACUS is a rating engine with its own configuration schema and its own API; a customer can put it behind a policy administration system that is not IPAL and never touch SRD_IPROD.

This is not speculation about the future — it is already how the code is arranged. ABACUS is reached by two routes, and only one of them goes through a database. IPAL's premium service calls the engine directly, assembling the request from its own pricing-factor declarations. A foreign PAS reaches it the same way. The SRD_INTEGR.ABC_* packages are a proxy for the incumbent system, not part of the engine. Figure 1 puts the two shapes side by side.

Figure 1. Two deployment shapes: ABACUS alone behind a foreign policy administration system, and ABACUS with IPAL. SHAPE 1 · ABACUS ALONE Customer PAS any vendor getRates ABACUS engine deployed rate versions SRD_ANLT.PPA_* the design-time surface Product Configurator writes a new version SHAPE 2 · ABACUS + IPAL IPAL SRD_IPROD · the product getRates ABACUS engine deployed rate versions group C INSIS (optional) via the ABC_* proxy
Figure 1 · Two deployment shapesShape 1 is the smaller product and the larger market. Shape 2 is what Bulstrad runs today; the dashed leg is the incumbent seam, which is separate work with a separate risk profile.
Scope groups, mapped onto the two shapes. The letters come from the existing scope menu and do not change.
GroupWhat it configuresShape 1Shape 2
B1–B3ABACUS: design, rate files, deploymentRequiredRequired
A1–A11IPAL: catalogue, covers, screen, packages, checks, print, accessNot applicableRequired
C1–C6INSIS contract, seam, numbering, request mapNot applicableOptional
The customer's own PAS mappingExported, not writtenn/a

In shape 1 the product needs a target adapter it does not have today. It can write ABACUS, but the customer's PAS still has to be told which covers exist and what to send in the rating request. The design's answer is not to build an adapter per PAS: it is to export a contract — the cover list, the factor list with types and allowed values, and a worked request/response pair — as JSON and as a human-readable page. Integrating that is the customer's side of the boundary.

02Architecture

Six services and two systems the product does not own, in figure 2. Nothing here is exotic; the only unusual decision is that the run is a first-class durable entity with its own state machine rather than a request handler, because it takes minutes to hours and must survive a restart.

Figure 2. The six services of the Product Configurator and the two systems outside it. Web UI runs · chat · workspace · docs API + OIDC client session · roles · audit Identity Server IPAL's OIDC · or any IdP Run orchestrator the state machine · gates resumable · survives restart Agent runtime prompts · tools · schemas emits a model, never SQL Model gateway Anthropic · OpenAI · Azure one key per tenant Workspace store inputs · model · outputs Estate prober SELECT only · returns counts Target adapter files · or a staged version Customer database SRD_ANLT · undeployed only
Figure 2 · The six servicesSolid arrows are the run path; the dashed arrow is authentication. The right-hand column is what the product does not own. The estate prober and the target adapter are the only components that touch a customer database, and they hold separate credentials with separate rights.

Service 1

Run orchestrator

The state machine

A run is a durable entity with a state, not a request. It survives restarts, can be paused at a gate for days while somebody answers a question, and is the unit everything else is keyed to: inputs, model, outputs, cost, audit.

Service 2

Agent runtime

Where the prompts live

The skills and prompts that are markdown files in the workspace today become versioned server-side assets. Each step declares its tools, its output schema and its model tier. No free-form generation reaches a database.

Service 3

Model gateway

Provider independence

One internal interface over Anthropic, OpenAI, Azure OpenAI and Bedrock. Handles keys per tenant, retries, token accounting and the fact that structured-output and tool-calling dialects differ. § 04.

Service 4

Estate prober

Read-only evidence

The isolated agent from the workspace, kept isolated. It answers „what does this column contain“ with counts and never with a recommendation, and it holds a credential that can only SELECT.

Service 5

Target adapter

The only writer

Two implementations behind one interface: emit files, or write an undeployed ABACUS version. Everything the service can write is enumerated in one place, which is what makes the write path reviewable.

Service 6

Workspace store

Everything a run touched

Content-addressed. Inputs are immutable once a run starts; outputs and the rendered document are versioned per run so two runs on the same product can be compared. § 07.

03The run

The eleven steps of the current skill collapse into seven states with three gates. A gate is a place where the run stops and waits for a person — not a checkpoint the model can talk its way past.

  1. Intake Files, a directory, a ZIP, or a link. Everything is unpacked, hashed and stored immutably. Office documents, PDFs and spreadsheets are converted to text and tables at this point, once, so that every later step reads the same rendition. The source set is frozen: a change to the inputs means a new run, not an edited one.
  2. Inventory Which file speaks to which part, which is authoritative, where two of them disagree. This is a report the user reads before anything is modelled, and it is the first place a missing tariff shows up.
  3. Scope GATE 1 The parts are proposed with what the spec covers, what it does not, and the consequence of leaving each out. The user chooses. In shape 1 the menu is group B only; in shape 2 it is A + B, with C offered separately.
  4. Model One canonical model, every line tagged SPEC, SYS or DEC. Held as structured data now rather than markdown, so the UI can render it, diff it, and list the open questions without parsing prose.
  5. Resolve GATE 2 Every DEC becomes a numbered question. The run cannot proceed while one is unanswered. Answers are recorded against the model with who gave them and when.
  6. Project The model is projected into artefacts: ABACUS design and rate files, IPAL SQL if in scope, an acceptance script, a rollback script, the PAS contract export, and the product document. Each artefact names the model section it projects.
  7. Verify GATE 3 The service calls getRates against the staged version and reconciles the returned premium against the tariff by arithmetic it did not itself invent. A run that cannot produce a reconciling quote does not reach Verified, and an unverified run cannot be deployed.

Gate 3 is the capability the workspace never had. The current refusal — „never report complete on a check derived from your own model“ — exists because a workspace with no execution rights cannot prove anything; it can only ask a human to check. A service with a connection can render the quote itself and compare it to the tariff document. That turns the strongest rule in the workspace from a warning into a test.

04The AI layer

The product must not be tied to one vendor: customers will have opinions about where their tariff documents may be sent, and some will require a model inside their own cloud tenancy. Provider independence is therefore a requirement, not a preference — but it is worth being precise about how much independence is achievable.

What the gateway must normalise, and what it cannot.
ConcernApproach
Chat + tool callsNormalised. All four target providers expose tool or function calling with the same shape: a declaration, a call, a result. The gateway maps to one internal form.
Structured outputNormalised, with a fallback. Where a provider supports a response schema natively it is used; where it does not, the gateway validates against the same JSON Schema and re-asks on failure.
Long documentsNot normalised — context windows differ by an order of magnitude. The intake step chunks and summarises to a common budget so the pipeline behaves the same on every provider.
Prompt cachingProvider-specific, and worth the special-casing: the knowledge base is the same on every run and is the bulk of the tokens.
QualityNot normalisable. A cheaper model will model a tariff worse. The gateway records which model produced which run so a regression is attributable, and the acceptance suite runs against each configured provider before it is offered to a tenant.

Two rules keep the model's mistakes inside the blast radius the design allows. The model never emits SQL that reaches a database. It emits the canonical model; the projection into SQL is deterministic code that a reviewer can read. And the model never holds a database credential — it asks the estate prober, which answers with counts.

The knowledge base travels with the product. What is in knowledge/ and memory/ today is Bulstrad's estate, and much of it is generic (the ABACUS rate-file grammar, premium vocabulary, the version-and-deploy model) while some is not (product codes, counted defaults, role names). The split has to become explicit: engine knowledge ships with the product; estate knowledge is measured per tenant on first connection and refreshed on a schedule.

05Writing into ABACUS

This is the section a reviewer should read hardest. The argument is that ABACUS already has the safety property we need, and the write path is safe exactly to the degree that it respects it.

A tariff in ABACUS is not a set of rows that the engine reads. It is a version, and the engine reads a compiled artefact produced when that version is deployed. The design-time tables and the runtime artefact are different objects:

LayerObjectRead by the engine?
designPPA_PRODUCT_COVERS.COVER_BP_RATING, PPA_PRODUCT_LD.LD_RATING — name the rating file per cover and per loadingNo
designPPA_PRODUCT_FILES (FILE_NAME, CONTENT) — the rate table itself; FILE_NAME is globally uniqueNo
runtimeRATING_TABLE_FILES (VERSION_ID, CSV_TABLE, PICKLE) — assembled at deploy, one artefact per versionYes

So an edit to design-time configuration changes nothing until the consuming version is deployed. That is normally described as a trap — it is the reason a corrected rate can look applied and price against the old numbers — but for a machine writer it is the safety net. The service writes a new version and stops.

The write contractWhat the adapter may do, stated as a list short enough to audit
  • New version only. The adapter creates a version in a non-deployed stage and writes beneath it. It never updates a row belonging to a deployed version, and it never writes RATING_TABLE_FILES at all.
  • Allow-listed tables. One enumerated list, in code, reviewed like any other security boundary. A table not on it cannot be written even if the model asks.
  • No DDL, ever. Schema change stays a human decision, and the run stops and asks — the existing refusal, unchanged.
  • Preview before write. The exact statements are rendered for approval, with a row-count estimate and a diff against the previous version.
  • One transaction, one audit record. Who, when, which run, which model, which statements, and the version id produced.
  • Undo is a drop, not a repair. Because the unit is a fresh version, reverting means discarding it. There is nothing to un-edit.
  • Deploy is not ours. A separate action, a separate role, a separate confirmation naming the blast radius: every version consuming a changed file must be re-deployed, and the service lists them.
Why not write IPAL the same wayGroup A has no version boundary, so the same argument does not hold

SRD_IPROD has no staging concept: a row inserted into PR_PRICING_FACTORS is live for the next quote. There is no deploy step to withhold and no artefact to leave un-built, so the mechanism that makes the ABACUS write safe does not exist on the IPAL side.

Recommendation: IPAL output stays files in the first release. If direct IPAL write is later required, it needs its own safety story — a product-scoped transaction with a generated rollback script executed as one unit, plus the observation that a half-configured product is invisible until its access rows exist, which suggests writing access last.

Connection modelWhere credentials live and what they may do
  • Two credentials per environment, never one: a read account for the estate prober and a write account for the adapter, the second granted only on the allow-listed tables.
  • The write account is granted per environment. A tenant may connect a test environment and keep production on file output — that is a supported configuration, not a degradation.
  • No connection at all remains a first-class mode: the product emits files and the verification gate falls back to a documented manual reconciliation.

06Correcting and reprocessing

Two loops, deliberately different. Confusing them is how a configuration drifts away from its own documentation.

Loop A

Correction

Chat, against the model

„The over-70 loading is 15 %, not 12 %.“ The assistant locates the model line, shows it with its tag and its source, and proposes the edit. On acceptance the model changes, the affected artefacts are re-projected, the document is regenerated and the verification gate re-opens. Only artefacts whose model sections changed are rewritten, and the run keeps its identity and its history.

Loop B

Reprocess

New input set, new run

A revised specification arrives. A new run starts from the new inputs and is diffed against its predecessor at the model level, so the user sees what the new documents actually changed rather than a wall of new SQL. Answers to open questions carry forward where the question is unchanged, and are re-asked where it is not.

The invariant that makes both loops safe: nothing edits an emitted artefact. A correction that cannot be expressed as a change to the model is a signal that the model is missing a concept — which is a finding worth surfacing, not a reason to hand-patch the SQL. The chat can refuse, and should.

A correction that lands after a version has been written to the database produces a new version, never an edit of the written one. The UI shows the chain: which version each run produced, which is deployed, and which are abandoned.

07The workspace, in the browser

Everything a run touched, in one place, addressable by URL. The workspace directory that exists on disk today becomes the object model of the UI — the structure is already right, it simply has to be served.

run / 7008-home-2026-09
│
├── inputs/                            # immutable · hashed · what was actually received
│   ├── tariff_2026.pdf                  # original bytes, plus the extracted rendition
│   ├── cover_matrix.xlsx
│   └── _inventory.md                    # file → date → parts it covers → authoritative for
│
├── model/                             # THE CANONICAL MODEL · structured, versioned, diffable
│   ├── model.json                       # every line tagged SPEC · SYS · DEC
│   ├── questions.json                   # open questions · owner · answer · when
│   └── history/                         # each correction, what it changed, who accepted it
│
├── output/                            # the projection · regenerated, never hand-edited
│   ├── abacus_design.sql                # group B · versions, covers, LD, factors
│   ├── abacus_rates/                    # the rate files · the never-derivable part
│   ├── ipal_product.sql                 # group A · present only in shape 2
│   ├── acceptance.sql                   # what proves it · run by the verification gate
│   ├── rollback.sql                     # file mode only — a written version is dropped, not undone
│   └── pas_contract.json                # shape 1 · covers, factors, a worked request/response
│
├── document/                          # the review artefact · HTML, rendered server-side
│   └── index.html                       # covers, tariff worked example, checks, gaps, open questions
│
└── audit/                             # who ran what, against which environment, with which model
    └── writes.jsonl                     # every statement the adapter executed, and its version id

The product document is the review surface, and it already exists: the workspace renders one per product from markers plus shared CSS. In the service it becomes a server-rendered page with the same content — covers and limits, the tariff with a worked example, what needs code, the gaps in the specification, the acceptance list — addressable, printable, and versioned alongside the run that produced it.

Retention and residency are tenant settings, because inputs are customer documents and some of them are commercially sensitive. A tenant must be able to say: keep inputs 90 days, keep the model and document indefinitely, and never send either to a provider outside this region.

08Identity and access

IPAL's login is already an OIDC server: the /identity-server microservice, an Ablera component in the same backend, exposing .well-known/openid-configuration and the /connect/* endpoints, federating the password check to the customer's directory with a failover tier behind it. That it is our component and speaks a standard protocol is what makes this section short.

Authentication, in the two shapes.
DeploymentIdentity providerBehaviour for a user already in IPAL
Shape 2
ABACUS + IPAL
IPAL's Identity Server, as a registered OIDC client No second login. Authorization Code with PKCE; the browser already holds a session with the same issuer, so the round trip returns without a prompt. Silent renewal uses prompt=none; only a genuinely absent session shows a login form.
Shape 1
ABACUS only
Any OIDC provider the customer runs, or local accounts as a fallback Ordinary sign-in. Nothing in the product assumes IPAL exists.

Roles come from the same vocabulary as the rest of the platform. IPAL already gates three different things with one role list — the menu through Routes."AllowedRoles", the API through EndPoints."AllowedRoles", and the check pipeline through its bypass roles. The configurator adds its own roles to that catalogue rather than inventing a parallel one, and appears in the menu on the same terms as any other product screen.

Proposed roles. Deliberately few, and split on the boundary that matters: who may change a live tariff.
RoleMayMay not
PC_VIEWEROpen runs, read models and documents, export filesStart a run; answer a question; write anything
PC_AUTHORStart runs, answer open questions, correct a model, emit filesWrite to a database; deploy
PC_WRITEREverything an author may, plus write a staged version to a connected environmentDeploy a version
PC_DEPLOYERDeploy a staged version, after confirming the blast radius
PC_ADMINManage connections, provider keys, retention, tenant settings

Two facts this design depends on, both of which need confirming before build. First, that the Identity Server will issue a client registration for a new application and include role claims in the token — IPAL's own role list lives in the database, so either the token carries it or the product reads it after authenticating. Second, that PC_WRITER and PC_DEPLOYER are acceptable as IPAL roles at all; they grant a power no existing IPAL role grants, and the customer's security owner should say so explicitly rather than inherit it.

09What exists, what is new

An honest accounting, because the workspace carries more of this than it looks and less than one would hope.

CapabilityStateNote
The configuration procedure — steps, gates, scope menuexistsMature and exercised; becomes the orchestrator's state machine
Domain knowledge — ABACUS, IPAL, premium vocabularyexists13 topic files, cut to configuration scope; needs the generic/estate split
Canonical model with SPEC / SYS / DECto formaliseToday prose in markdown; becomes a schema so the UI can render and diff it
The two isolations — tariff reader, estate proberexistsPort as-is; the isolation is the point and survives the move
Product document generationexistsMarkers plus shared assets; becomes server-side rendering
Read-only database accessexistsPer-user connections today; becomes per-tenant service credentials
Model gateway, multi-providernew§ 04
Intake: ZIP, directories, office formats, OCRnewThe extraction quality bounds everything downstream
Write adapter and the staged-version contractnew§ 05 — the highest-risk component
Automated verification gatenewCalls getRates and reconciles; the workspace could never do this
Web UI, chat correction loop, run diffingnew§ 06, § 07
OIDC integration and role modelnew§ 08 — small, given the identity server already speaks the protocol
Multi-tenancy, retention, residencynewNot deferrable: it shapes the data model from day one

10Decisions, and what they beat

ABACUS first, IPAL optionalRejected: keep IPAL as the anchor and treat ABACUS as one of its surfaces

The rejected shape is how the workspace is written today, and it makes the product unsellable to anyone who does not run IPAL. Anchoring on ABACUS costs one thing — the PAS contract export in shape 1 — and buys the larger market. The code already supports it: the engine is called directly and knows nothing about which system called it.

The model is data, not proseRejected: keep the markdown model and parse it for the UI

Prose is why the current model is readable, and that is worth preserving in the rendered document. But diffing two runs, listing open questions, showing which artefact projects which section, and re-projecting only what changed all need structure. The document is generated from the data, so nothing is lost.

Write a version, never a rowRejected: transactional writes with a generated rollback script

A rollback script is a repair, and repairs assume the damage is known. A new version is an isolation: whatever the service got wrong is confined to an artefact nothing reads until somebody deploys it. It also matches how tariff changes are actually promoted, so nothing unusual has to be explained to the customer's change process.

The agent never emits executable outputRejected: let the model write SQL and review it before execution

Model-written SQL is reviewable exactly once, by whoever is looking that day. Deterministic projection from a validated model is reviewable permanently, in code, by people who never see a particular run. It also makes the output stable: the same model produces the same SQL, which is what allows two runs to be diffed at all.

Deploy is a separate role and a separate actRejected: deploy automatically once verification passes

Tempting, because the verification gate is genuinely strong. It is refused because deploy has a blast radius the run cannot see: a rate file is shared, and every version consuming it must be re-deployed together. That is a decision about other products, and it belongs to a person who can see them all.

11Open questions

Tagged the way the configurator tags its own gaps. Each one changes the build if answered the other way, and none of them should be settled by the person who wrote this document.

#QuestionWhy it matters now
DEC-1Is the first release file output only, with the ABACUS write path following in a second release?Decides whether § 05 is in scope for the first delivery, and therefore roughly half the security review.
DEC-2Single-tenant per customer install, or one multi-tenant service?Shapes the data model, the credential store and the deployment story. Cannot be retrofitted cheaply.
DEC-3May customer tariff documents leave the customer's cloud region, and which providers are acceptable?Determines whether the model gateway must support in-tenancy deployments on day one.
DEC-4Will IPAL's Identity Server issue a client registration for this application, and will role claims travel in the token?If not, the product reads roles from the database after authentication — workable, but a different integration.
DEC-5Who owns PC_DEPLOYER at a customer, and does that role already exist in another guise?It grants a power no current IPAL role grants; it should be granted deliberately.
DEC-6What is the acceptance bar for a tariff the service configured — a reconciling quote, or a set of them across a factor matrix?Defines gate 3 precisely, and with it the meaning of the word Verified in the UI.
DEC-7How is engine knowledge kept current as ABACUS changes, and who owns that knowledge base once it ships to customers?Every count in it carries a measurement date; a shipped knowledge base rots silently.

12Delivery, in an order that can be stopped

Each stage is usable on its own, and each is a defensible place to stop if the next one does not earn its risk.

StageDeliversUsable because
1Service skeleton: intake, orchestrator, agent runtime on one provider, file output, the run workspace and the product document, OIDC loginIt is the workspace with a web front end and no per-user setup. Every current user is served.
2The model as data: structured canonical model, open questions as objects, the correction chat, run diffingCorrections stop being a re-run. This is where the tool becomes pleasant rather than merely capable.
3Read connection: estate prober per tenant, measured defaults, the automated verification gateThe service can now prove a premium instead of asking a human to. Still writes nothing.
4The ABACUS write path: staged version, preview, allow-list, audit, deploy hand-offThe full loop, with the highest-risk component arriving last and alone, against a product the reviewer already trusts.
5Shape 1: PAS contract export, non-IPAL identity, multi-provider gatewaySellable outside the IPAL estate.

Stage 3 before stage 4 is the load-bearing sequencing decision. A service that can verify but not write is a genuinely useful product and a safe one. Arriving at the write path with verification already proven means the riskiest component is the only new thing under review, and it is reviewed against a system whose output is already trusted.