Tester user guide — Unified Insurance Solution Pack (powered by TurfAI)
This guide explains the whole demo insurer for people who test it: every flow, every role and what it does, who approves what and when, every TurfAI workflow, and a catalogue of scenarios with the result to expect. It is written from the code (task kinds, decision handlers, router, mappers, workflows and UI labels as of P16.5, sim date 2026-11-01 onwards). Button labels are quoted exactly as they appear in the UI.
Setup, environment variables and commands are in the root README; the full design is in
brd/unified_app_plan.md.
Contents
- What the system is
- Roles and their tasks
- End-to-end flows
- Who approves what, when (master table)
- The TurfAI workflows
- Scenario catalogue
- Tips, gotchas and known bugs
- Glossary
1. What the system is
A demo life insurer ("TurfLife") that runs TurfAI's eight Life Solution Packs — Underwriting, Issuance & Servicing, Billing, Renewals, Claims Intake, Fraud & SIU, Claims Settlement, Complaints — as one connected company. A policy applied for on the portal is underwritten, issued, billed, renewed, serviced, claimed on and complained about, and each pack hands its result to the next.
1.1 The principle: TurfAI decides, people approve, the app orchestrates
- Every insurance judgement is made inside a TurfAI workflow: rating, requirement lists, issuance checks, collection instructions, dunning stages, reconciliation matching, renewal outreach, servicing answers, claim triage, fraud scoring, SIU dispositions, coverage and valuation, complaint classification and deadlines, and every letter or message a customer reads.
- The app never decides. It only
- orchestrates — routes events to workflows, branches on the routing fields TurfAI returns, holds human approvals, and runs the simulated clock;
- plays the insurer's systems — its Postgres database is the CRM / policy administration system; the deterministic non-AI systems are mocks: rating engine (premium tables), payment rail (NACH / UPI AutoPay / card debits), bank settlement feed, AML / PEP / sanctions list, hospital records service, revival quote;
- shows it — the customer portal and the operations / RM console.
- Humans approve — at HITL. Almost every TurfAI result lands as a human task in a role's inbox. At the default autonomy level, HITL (human in the loop), nothing is issued, lapsed, paid, repudiated, sent to a customer or closed until the right person chooses an option. The level (Console → Clock, §1.8) decides which clean gates go straight through: at Semi-auto the orchestrator's autopilot closes a clean standard underwriting memo, a complaint acknowledgement and a renewal outreach itself; at Autonomous also a clean settlement sign-off up to a pay-out limit and an unsubstantiated SIU disposition. The autopilot never judges: it applies TurfAI's own recommendation, and only when TurfAI's routing fields say the case is clean and the insurer's System checks found 0 mismatches and the level permits that gate. Every other gate waits for a person at every level.
- Push model. The worker sends TurfAI the full context as signed webhook JSON and polls for the result; TurfAI never calls back into the app. Each result is checked against a strict contract before the app uses it.
- The insurer double-checks the arithmetic. Before using a TurfAI result the app recomputes every deterministic fact it can (ages, dates, amounts, windows, copies of routing fields) and shows disagreements on the task as (see ).
1.2 Starting it
Follow the README: npm install, fill .env.local, provision the workflows, then
npm run demo:reset # fresh demo data, clock at 2026-11-01
npm run dev # web on http://localhost:3100 + the worker
Without the worker nothing reaches TurfAI: pages render, but submitted work waits.
| URL | What |
|---|---|
| http://localhost:3100 | Landing page — pick a storyline |
| http://localhost:3100/portal | Customer portal |
| http://localhost:3100/console | Operations / RM console (Inbox) |
/console/policies | Policy 360 — "Find a policy" by policy number or customer name; one timeline per policy / proposal |
/console/complaints | Complaints register and root causes across the book |
/console/runs | Runs — every TurfAI execution, its inputs, contract and status |
/console/dashboards | Pack dashboards (all eight packs) |
/console/clock | Simulated clock, advance controls, Reset demo… |
1.3 Portal and console
Customer portal (/portal). The Act as menu (top bar) picks which customer is using the portal. When the
insurer knows a customer has died (a claim was reported), the portal acts as that customer's nominee (e.g. A2's
son Karthik, B's wife Anita). Sections:
| Portal page | What the customer does there |
|---|---|
| Apply | Fill the proposal form, attach / upload documents, optionally Pay the first premium now, submit; follow the decision; answer a request for more information ("Send to underwriting") |
| My policy | Schedule, status, risk commencement, free-look end, nominee, premium paid-to date, policy documents |
| Ask about my policy | Ask a question, request an endorsement (nominee, address, phone / e-mail, premium mode), a premium-paid certificate, a free-look return, or a revival |
| Payments & mandate | See dues and messages; Pay ₹… now; Re-register mandate; I'm having difficulty paying; Ask to revive this policy / Pay ₹… and revive |
| Offers | Answer a revised underwriting offer, or a renewal / retention offer |
| Report a claim | Report a death (form + plain-text documents), follow the claim, read the decision letter. While a claim on the selected policy is not closed, the page says "You already have claim CLM-… (<status>) on this policy — its progress is shown above" and folds the form behind Report this death again (a second report is still allowed — §3.4). A claim waiting for documents ("More documents needed": asked at triage or at settlement) shows what is still needed — the claims officer's note and TurfAI's list — and an Add documents form on the claim card (same upload list and Use sample documents as Report a death); the documents go to the same claim and TurfAI checks / re-assesses it () |
Operations / RM console (/console). The Work the inbox as menu picks a role; the badge shows its open
tasks. The Inbox has Open / Decided views and an All / Storyline / Background filter (storyline personas
vs the background book). In the Decided view a task the autopilot closed carries an Autopilot badge next to
its status (§1.8). Clicking a task opens the task drawer: TurfAI's contract
rendered for that kind of task, System checks, the case panels (claim, SIU, billing, …), Lineage (the TurfAI
run, the triggering event, the source documents as chips), the Decision card and the full payload. The drawer is
laid out so the decision is never out of reach:
- Sticky header with jump chips. Under the title a row of chips — Summary · Checks · Recommendation (or the case block: Claim, SIU case, Billing, …) · Lineage · Decision · Payload — is built from the sections actually on the page; a click scrolls that section under the header. The Decision chip is highlighted.
- The Decision card is the accented box (primary border, sparkle icon) with a state badge: Your call (open, yours to decide), Decided, Decided by Autopilot, Cancelled, or Awaiting <role> when the task belongs to another console role ("This task belongs to the Underwriter — switch role to work it"). Claim reserves the task for you; Release gives it back. Deciding an open task claims it automatically. The options are radio buttons; choosing one shows the extra fields it needs and a short "what happens next" text; then Submit: <option>. On the underwriting memo, the option TurfAI recommends carries a small TurfAI sparkle marker. On the settlement sign-off and the SIU disposition — whose single option signs TurfAI's result off as it is ("Sign off TurfAI's recommendation / disposition") — the card opens with a line saying what that result is, e.g. "TurfAI recommends: Admit the claim — pay ₹27,67,173 to Karthik Iyer (son)", "Repudiate the claim — s.45 non-disclosure; refund premiums of …" or "Substantiated — send repudiation grounds to Claims Settlement" ("TurfAI recommended: …" once decided). It is read straight from TurfAI's routing in the task payload.
- The sticky "Decide:" bar at the bottom of the drawer shows one button per option (the recommended one with the TurfAI sparkle) while the Decision card is off-screen: clicking a button selects that option and scrolls the card — with its form open — into the middle of the view; the bar fades as soon as the card is in view and is not rendered for decided / cancelled tasks. For another role's task it says Switch to <role> to decide; for a held settlement sign-off it shows the held text ("Sign-off held: …") and no buttons.
- Other claims on this policy. On a Claim triage — and on a Settlement sign-off when the policy has another claim — the drawer opens with an amber box "Other claims on this policy" (badge insurer's claims records); its chip is the first in the header row. It lists the insurer's other claims on the policy, warns when TurfAI did not link an open one, and links to each claim's Policy 360 and open task ().
A storyline panel (floating, collapsible, on every page) is the presenter guide: current beat, whom to act as, a link to the right page, which TurfAI pack is working, and what to point out.
1.4 Personas
All people are fictional; amounts are INR. Customer ids, policies and dates come from fixtures/personas/*.json
and plan §15.
| Persona | Starting state (seed) | What it demonstrates |
|---|---|---|
| A1 · Arjun Rao (b. 1994-06-14, 32, non-smoker) | Draft application PRP-2026-000101: TL-SECURE-TERM, ₹1,00,00,000, 30 years, monthly ₹1,404, NACH mandate NACH-MND-88319, nominee Divya Rao (spouse). KYC, ITR and proposal form on file | Straight-through: apply → standard → issued POL-LIFE-2026-000101 → 12-01 premium collected → 12-02 bank feed matched. Also the requirements path (send without ITR / KYC) |
| R1 · Kavya Menon (b. 1985-02-20, 41) | Draft application: ₹50,00,000, 20 years, annual. KYC, medical exam and lab report on file | Rated case: underwriter rates +50 % → Kavya accepts ₹17,346 on Offers → POL-LIFE-2026-000102 |
| A2 · Meena Iyer (b. 1965-04-02) | Endowment POL-LIFE-2019-000311, ₹25,00,000, RCD 2019-03-01, vested bonus ₹3,40,000, policy loan ₹60,000 + interest; died 2026-10-25 | Clean death claim (11-02, nominee son Karthik): fraud low → settled for sum assured + bonus − loan |
| B · Vikram Sethi (b. 1982-01-17) | Term POL-LIFE-2025-000877, ₹40,00,000, RCD 2025-09-10, proposal disclosed no conditions; died 2026-11-03 | Early claim (11-08, wife Anita): hospital records show hypertension + diabetes since 2020 → fraud refers → SIU substantiated → s.45 repudiation → Anita complains (11-25) |
| C · Lakshmi Narayanan (b. 1976-08-09) | Endowment POL-LIFE-2021-000452, ₹15,00,000, RCD 2021-06-15, ₹4,200 monthly NACH due on the 15th | Billing to claim: 11-15 debit fails → 11-20 retry fails → 11-22 hardship → retention outreach → 12-01 lapse → 2027-01 revival with health declaration → monthly premiums → 2028-05-20 death in grace → SIU screen clears → ₹16,74,300 settled (in-grace premium deducted) |
1.5 The simulated clock
Every component reads time from one simulated clock (clock.sim_now), never the wall clock, and every TurfAI run is
given as_of_date = the simulated business date. The clock only moves forward.
On Console → Clock: +1 day, +7 days, +30 days, To next event (date), and Advance to date → Advance. Every day in between is scanned in order. Before each day the clock waits (up to 5 minutes) for the storylines' in-flight TurfAI work to finish, so a multi-day jump does not overtake a run; if it times out you see "Advance stopped early" with the reason.
What the daily scan does (no judgement — it compares dates held in the CRM):
| Scanner | When | Result |
|---|---|---|
| Billing schedule | a premium-paying policy has no future due | next instalment row created |
| Premium due | a scheduled due's date ≤ today | premium.due → TurfAI billing_collect |
| Dunning step | the next dunning action date ≤ today | dunning.step_due → mock rail retry and / or TurfAI billing_dun |
| Grace end | grace end ≤ today on an unpaid due | grace.ends (timeline fact) |
| Grace expiry | grace end < today on an unpaid due | billing.grace_expired + Grace expired task for the collections officer (the app never lapses by itself) |
| Renewal window | a scheduled due enters a window (annual 90 / 60 / 30 / 7 days before, half-yearly 30 / 7, quarterly 15 / 7, monthly 7) | renewal.window_open → TurfAI renewal_action |
| Complaint risk | a complaint's escalation trigger date ≤ today |
Why dates matter. Cover is judged on the date of death; contestability (s.45) runs 3 years from the later of RCD and last revival; grace is 15 days for monthly and 30 days for other modes; complaint clocks run from the received date (acknowledge 3 days, resolve 14 days, escalate on day 10); revival quotes are valid 5 days. Play the storylines in date order: A1 + R1 on 11-01 → A2 on 11-02 → D on 11-07 / 11-08 → B from 11-08 and C from 11-15 interleaved → A1's December premium (12-01 / 12-02) → C's 2027–28 beats last. Once the clock has passed a beat's date, that beat cannot be replayed without a reset.
1.6 Reset demo
Console → Clock → Reset demo… opens "Reset the demo?" → Reset demo. It is the same as
npm run demo:reset: every proposal, policy change, payment, claim, complaint, task, sign-up and TurfAI run made
during the demo is deleted, the database is re-seeded, the clock goes back to 01 Nov 2026, and TurfAI runs still in
flight are abandoned (their results are never applied). It only works on the uip database on localhost:5544.
1.7 Demo scopes (cost control)
TurfAI runs cost tokens. reference_data['demo.settings'] limits which billing / renewal events go to TurfAI:
| Setting | Values | Default (setting absent — what demo:reset leaves) |
|---|---|---|
turfai_billing_scope | all (whole book) · personas (storyline customers and sign-ups — anyone not bg-…) · none | personas |
turfai_renewal_scope | same; when absent it follows the billing scope | personas |
So by default background policies' premiums are not collected through TurfAI and simply run to grace expiry (you will
see their Grace expired tasks under the Background filter). With billing scope none the bank feed is not
reconciled either. There is no console toggle for the scopes (§13.1 K10); they are changed by SQL only. The same
row's autonomy key is the autonomy level, which does have a console control — next section.
TurfAI focus (test one storyline faster). A clock jump waits, day by day, for every storyline persona's TurfAI
runs, so moving A1 from issuance to its 01-Dec due also waits on C's renewal windows, D's complaint re-check, bank
feeds and so on. In the storyline panel, Focus TurfAI on this storyline stores turfai_focus_persona in the same
row. While it is on, only that persona's events (and bank feeds with a line on its policies) go to TurfAI. The other
storylines' events are kept, not dropped: they wait unprocessed, the clock does not wait for them, and their tasks
are not held. The panel shows how many are waiting. Turn focus off (or focus another storyline) and the worker
catches up on them, routing on the CRM as it is then. Reset demo clears the focus. Background customers are not
affected; the scopes above still govern them. While focused, the other storylines' dues still pass their grace dates
without a TurfAI collection, so expect their Grace expired tasks. Reset before running those storylines properly.
1.8 The autonomy level (autopilot)
A demo setting (reference_data['demo.settings'].autonomy = {level, payout_limit}, plan D30) that says which clean
TurfAI results the orchestrator may close itself by applying TurfAI's own recommendation. Absent / unreadable → HITL.
Setting it. Console → Clock → Autonomy level card: three radios with their meaning —
| Radio | Meaning (as shown) |
|---|---|
| HITL | Every TurfAI result waits for a human. (The default; what demo:reset leaves.) |
| Semi-auto | Clean standard underwriting memos, complaint acknowledgements and renewal outreach go straight through. |
| Autonomous | Also clean pay-outs up to the pay-out limit and unsubstantiated SIU dispositions. |
Under the radios an amber note (also at the foot of the storyline panel) reads: "Autonomous — demo only: the specs have a claims officer approve every claim; the autopilot never repudiates, never signs a substantiated fraud case and never pays above the limit." (P16.5, D-12 — copy only; the level behaves exactly as described here.)
— then Pay-out limit (INR, Autonomous only) (whole rupees, a ₹ preview beside it; default 5000000 = ₹50,00,000;
"a clean settlement with net payable up to ₹… is signed off automatically; anything above it waits for the claims
officer"), the help line Never automatic at any level: issuance review, lapse, hardship / collections, billing
mismatch, reconciliation, servicing, revival, claim triage, SIU screen / investigation, complaint resolution /
escalation, regulator notice, run failure, every customer task — and Save autonomy level. Under the button: "Applies to the next TurfAI
result; open tasks are not re-evaluated; a demo reset returns to HITL." Saving shows "Autonomy: Semi-auto · pay-out
limit ₹50,00,000 — Saved. The next TurfAI result the worker maps runs at this level; tasks already open keep waiting
for their role." (or "Already set — nothing changed."); an invalid limit is refused with "Not saved". The save takes
the demo lock, so it is refused while a clock advance or a reset is running. The console frame (not the portal) shows
the current level as the badge Autonomy: HITL / Semi-auto / Autonomous at the right end of the console tab row (Inbox … Clock); it links to the
card (/console/clock#autonomy).
What the autopilot does (apps/worker/src/autonomy.ts). Right after a mapper has written a TurfAI result into
the CRM and raised one of the five gate tasks below, the worker reads the level and evaluates the gate's checks on the
task payload — TurfAI's routing.* fields plus the insurer's recomputed System checks. Every check must pass and
the level must permit the gate; then the task is decided as system:autopilot with the option TurfAI recommended,
inside the same transaction, and the follow-on events fire exactly as if a person had clicked:
| Gate (task kind) | From level | Checks (all must pass) | Decision applied |
|---|---|---|---|
Underwriting memo (uw_memo) | Semi-auto | decision_type standard · no referral (refer_to empty) · no outstanding requirements · compliance_pass true · loading 0 % · no exclusions · no over-insurance · 0 system-check mismatches | Accept (standard) → uw.approved → policy_issue |
Complaint acknowledgement (complaint_acknowledgement) | Semi-auto | acknowledgement required · no human review required · not escalated · TurfAI's draft present · 0 mismatches | Send TurfAI's acknowledgement → complaint.acknowledged + resolution task (owner stays unassigned — a system:* actor is never made the case owner) |
Renewal hand-off (renewal_handoff) | Semi-auto | stage hand-off (not a follow-up) · sendable (consented channel + draft) · not escalated · handed off to the RM (not a broker) · cadence not stopped · 0 mismatches | Send TurfAI's draft → renewal.outreach_sent + customer offer |
Everything else is never automatic (the list on the card). A rated / exclusion / counter-offer / decline /
requirements memo, an escalated complaint, a repudiation, a substantiated disposition — all wait for their role at
every level. The autopilot also respects the task engine's own rules: when the engine refuses the decision (e.g. the
customer opted out, the sign-off is held) the task stays open with a crm_changes autopilot_skipped note.
Where you see it.
- Inbox → Decided: an Autopilot badge beside the status of the row.
- Task drawer: fact "Decided by: Autopilot"; the Decision card's badge reads Decided by Autopilot and the card
says "Decided by Autopilot · Semi-auto · 8 checks passed on <date> — TurfAI's recommendation (Accept (standard))
applied by the orchestrator; nothing was judged in the app." followed by the Autopilot checks chips (one per
check, e.g.
decision_type standard,no referral,compliance_pass true,loading 0 %,0 system-check mismatches). - Task drawer, open task: when the level permitted the gate but the autopilot left the task to a person, the Decision card opens with one muted line — "Left to you by the autopilot (Semi-auto): referred to senior · compliance_pass false" (the failing checks; "skipped — <reason>" when the task engine refused the decision).
- Storyline panel ("Show the story and every beat"): a beat the autopilot completed carries the subtitle "auto-approved — TurfAI's recommendation applied by the autopilot" (A1 memo, A2 sign-off, B acknowledgement, C outreach; R1's rated memo and B's substantiated disposition never do).
- Policy 360 timeline: the decision event (
uw.approved,claim.approved, …) is listed with sourcesystem:autopilot, and the CRM change rows namesystem:autopilotas the actor. - Dashboards: Underwriting, Renewals, Fraud & SIU, Claims Settlement and Complaints cards have an Auto-approved
share tile — decided tasks of the pack's autopilot gate decided by
system:*÷ decided tasks of that gate (dashes until one has been decided). - Audit trail: every save writes a row on subject (table , row , actor , ); an autopilot decision has , a decision note "Auto-approved by the autopilot (semi_auto): TurfAI recommended accept; …" and event ; and the task payload carries an stamp (+ on a sign-off). The stamp is written whenever the level permits the gate — with and the failing checks when a person had to decide (the Decision card's "Left to you by the autopilot" line; the full stamp is in the drawer's section), and when the engine refused. At HITL nothing is stamped.
Not retroactive. The level is read when a TurfAI result is mapped. Raising it does not touch tasks already in
an inbox, and lowering it does not undo anything. The one re-evaluation: a held settlement sign-off is re-checked when
fraud.cleared releases it (at the level current at that moment). Reset demo drops the setting → HITL.
1.9 Sample documents
Testers do not need the storyline files on their machine. The two upload forms that take a scenario's evidence offer it in one click:
- Portal → Report a claim: Use sample documents next to the documents list (and Use sample email inside the intimation e-mail section when the set has an e-mail — C). The Add documents form on a claim waiting for documents offers the same sets (P16.2).
- Console → SIU investigation → Submit findings: Use sample documents below the file inputs (findings file and evidence uploads) — only for the SIU investigator role; other roles see no findings samples.
Report a death opens pre-filled. When the Act as persona has a claim sample set, the "Report a death" fields (date of death, cause, place, your name, relationship, phone, e-mail) open filled from that persona's sample claim form, marked Sample details with a Clear button (back to the plain defaults: the nominee's name and a date of death the insurer already knows). Every field stays editable and the policy selection is yours; Use these documents on a set fills the fields again from that set's claim form and attaches its documents, so a storyline claim is Use sample documents → Use these documents → Submit claim with nothing typed. A set that would take the upload list over 10 documents is refused with a message (remove some of your files first); a sample e-mail never overwrites text you typed in the intimation e-mail box without asking.
The button opens "Sample documents for this customer": one card per set with its title, where it fits in the storyline, a summary, the Expected outcome and the file list. Use these documents adds the files to the form's upload list as ordinary entries marked Demo sample text — the kind (claim) or slot (findings / evidence) can still be changed, each entry can be removed or read ("Show the sample text"), and your own files can still be added. Using another set replaces the samples of the first one (your own files stay). On the findings form the set's relied-on documents are pre-ticked when they are on the task (using another set or removing the set's file takes those ticks away again; ticks you made stay), and if you also choose a findings file it replaces the sample findings (the form says so). TurfAI reads the text exactly as if you had uploaded the file.
Only the current customer's documents. On the portal the list holds only the documents of the persona selected in Act as; in the console, only those of the customer whose claim the open SIU investigation is about. The server decides this from the Act as selection / the task on every request — another persona's set or file is simply "not found" (also for downloads).
Download to edit. Every file has a Download link (a .txt attachment). Download it, change what you want to
test (a name, a date, the conclusion line) and upload your copy with "choose files" instead of the sample.
| Act as (portal) / task (console) | Form | Set (as shown) | Expected outcome |
|---|---|---|---|
| A2 · Karthik Iyer | Report a claim | Clean death claim — Meena Iyer | S6: intake fast-track, fraud low (cleared), settlement admits ₹25,00,000 + bonus − loan for the claims officer's sign-off |
| A2 · Karthik Iyer | Report a claim | Death certificate that does not match (C2) | C2 — run it instead of the clean claim, on a fresh demo:reset: intake may hold / ask for documents; if registered, fraud expected to find document forensics → high → SIU. Reported after the clean claim it is a second report of the same death — that is the separate case "C2 after the clean claim" (§6.4) |
| A2 · Karthik Iyer | Report a claim | Report the same death again (S6 duplicate) | After the clean claim CLM-2026-000311 is registered (or further: awaiting sign-off / fraud) — click Report this death again first, the form is folded while 311 is open: the same five files and details again → intake links it as a duplicate of CLM-2026-000311 (letter duplicate link) → the claims officer's triage offers Link as duplicate (C3 in §6.4) |
| A2 · Karthik Iyer | Report a claim | Incomplete death claim — claim form and death certificate only (P16.2) |
No sample documents (no button): A1, R1, N1 and new sign-ups (new-<n>) — they have no claim in their
storylines; Apply and Requirements keep their own generated Use a sample documents (§7.1).
The constructed fraud scenario s5_siu_findings.txt (UNSUBSTANTIATED, C10) is not offered: no seeded customer owns
its policy (it is about claim CLM-2026-000743). Changing only the conclusion line of B's findings does not make an
unsubstantiated case: a conclusion that contradicts F1–F9 gets no outcome from TurfAI (C8's result).
The files are the repo's fixtures, unchanged (fixtures/documents/<persona>/, fixtures/documents/samples/,
turfai/fixtures/claim_intake/docs/, turfai/fixtures/fraud_dispose/docs/).
2. Roles and their tasks
The console roles come from HUMAN_TASK_ROLES; the task kinds, owners and options from TASK_KINDS
(packages/db/src/tasks/kinds.ts); what each option does from the decision handlers
(packages/db/src/tasks/handlers/*.ts). "Note (required)" means the note field must be filled for that option.
Ten console roles plus the customer (the earlier Finance, SIU and Head of Grievance Redressal desks were merged into
Collections & finance, SIU lead and Compliance & grievance). TurfAI's own routing words are unchanged — a reconciliation
exception is still "for review by finance", a dunning case is still "routed to a collections officer", an escalation
still names "the Head of Grievance Redressal" — those name the route; the table names the desk that works it.
| Role (console label) | Task kinds (inbox label) |
|---|---|
| Underwriter | Underwriting memo |
| Customer (portal) | Counter-offer · Renewal / retention offer · Revival payment |
| Servicing officer | Issuance review · Servicing escalation · Revival request |
| Collections & finance | Grace expired · Collections review · Billing check · Reconciliation exception |
| Relationship manager | Renewal hand-off |
| Claims officer | Claim triage · Settlement sign-off |
| SIU lead | SIU screen · SIU disposition sign-off |
| SIU investigator | SIU investigation |
| Complaint owner | Complaint acknowledgement · Complaint resolution |
| Compliance & grievance | Claim triage (screening hit) · Complaint escalation (whoever TurfAI escalates to) · Regulator notice sign-off |
| System (ops) | System — run failure |
2.1 Underwriter — "Underwriting memo" (uw_memo)
Raised by the uw_assess mapper for every assessment (first application and every requirements answer). Shows
TurfAI's memo: headline, decision and loading, rating factors with debits / credits and the manual sections they cite
(UWM-n), requirements with status (outstanding → satisfied → not required), non-disclosure flags, KYC / AML,
financial underwriting (aggregate cover, income multiple, justified sum, over-insurance), the drafted letter, and
System checks (age, aggregate cover, income multiple, justified sum, over-insurance, loading recomputed from the
manual). The option TurfAI recommends carries a small TurfAI marker; Rated pre-fills TurfAI's loading /
exclusions; Request requirements pre-fills TurfAI's outstanding items.
| Option (button) | Fields | Rule (refused otherwise) | What happens |
|---|---|---|---|
| Accept (standard) | — | no loading, exclusions or changed terms | proposal approved → uw.approved (standard) → TurfAI policy_issue runs |
| Rated / exclusion | Loading %, Exclusions (one per line) | loading > 0 and / or ≥ 1 exclusion; sum assured and term unchanged | proposal offer_pending; the rating engine re-prices; customer Counter-offer task on portal Offers. Nothing issues until the customer accepts |
| Counter-offer | Sum assured (₹), Term (years), optional loading / exclusions | sum assured and / or term changed; sum assured not above the proposed one | as Rated — re-priced offer to the customer |
| Decline | Note (required) | no terms | proposal declined; nothing issued |
| Request requirements | Requirements (one per line) | at least one item | proposal ; the customer sees the list on Apply and answers with documents |
Every option emits uw.approved {decision}; only standard routes to issuance. The customer letter is TurfAI's
draft and is attached only when your decision is the one TurfAI wrote it for (same option as its recommendation, same
loading / exclusions / sum / term, same requirement list). Otherwise no letter goes out and the form tells you why
before you submit (e.g. "the decided terms are not the ones TurfAI's letter states: loading 75 % vs TurfAI's 50 %").
The app never writes or edits a letter.
At Semi-auto or above a clean memo — standard, no referral, no outstanding requirements, compliance pass, loading 0, no exclusions, no over-insurance, 0 System-check mismatches — is accepted by the autopilot before it reaches the inbox (§1.8); it appears under Decided with the Autopilot badge and issuance starts at once. Anything else waits for you as at HITL.
2.2 Customer (portal) tasks
| Task | Where | Options | What happens / refusals |
|---|---|---|---|
Counter-offer (counter_offer) | Offers → "Revised offer from underwriting" | Accept / Accept and pay ₹… → Confirm acceptance; Decline → Confirm decline (optional reason) | Accept → uw.offer_accepted → TurfAI policy_issue. If the first premium was not paid at Apply, accepting pays the quoted premium; if a smaller amount was paid at Apply, a top-up is collected; if more was paid than the revised premium, accepting is refused ("a refund of the excess is not supported"). Decline → proposal offer_declined → uw.offer_declined; nothing else happens |
Renewal / retention offer (renewal_offer) | Offers ("We'd like to help you keep your cover" / renewal reminder) | Accept / Decline (+ optional note) | renewal.offer_accepted / renewal.offer_declined + an RM follow-up hand-off. Changes no billing or policy status. Refused once the touch is closed / superseded |
Revival payment (revival_payment) | Payments → Pay ₹… and revive |
Only the customer who owns the proposal / policy can answer.
2.3 Servicing officer
Issuance review (issuance_review) — raised by policy_issue when TurfAI flags the issuance non_standard, or
any recomputed issuance fact (policy number, sum assured, term, premium, mode, grace days, loading, exclusions,
issue / RCD / free-look / maturity dates, status vs first premium receipt) disagrees with the contract.
| Option | Rule | What happens |
|---|---|---|
| Confirm issuance | the CRM holds a confirmed first premium with a receipt; the stored plan's next due and free-look end are not in the past | issuance.confirmed, then the policy is written with the insurer's recomputed plan (never TurfAI's values): policy, nomination, mandate, documents, billing schedule, policy.issued |
| Reject | Note (required) | proposal issuance_rejected → issuance.rejected; nothing issued. The plan says "re-run the issuance from the current date", but there is no UI to re-run it |
Servicing escalation (servicing_review) — raised by policy_service when TurfAI declined a question (out of
scope), held a change, a generated certificate / applied change disagrees with the insurer's figures, or the CRM
could not write an applied change. Options depend on the case:
| Option | When offered | What happens |
|---|---|---|
| Reply to the customer | always | "Your reply to the customer (required)" goes to portal Ask beside TurfAI's message → servicing.resolved (replied) |
| Apply the change | a held change with a CRM record action, and TurfAI's values equal the customer's request | writes TurfAI's validated change (nominee, address, contact, premium mode, free-look cancellation) → servicing.resolved (applied); refused if the values cannot be written or differ from the request |
| Decline | always | "Reason, shown to the customer (required)" → servicing.resolved (declined); nothing changes |
Revival request (revival_review) — every revival request is held for the officer (TurfAI never revives).
| Option | Rule | What happens |
|---|---|---|
| Approve the revival | policy still lapsed; quote not expired (valid 5 days); the billing schedule still gives the same total | request approved → servicing.revival_approved + customer Revival payment task for the quoted total. Otherwise refused ("the revival quote expired…", "the billing schedule changed since the quote…") — the customer must ask again |
| Decline the revival | "Reason, shown to the customer (required)" | servicing.resolved (revival declined); policy stays lapsed |
2.4 Collections & finance — collections tasks
Collections review (collections_review) — raised by billing_dun when TurfAI routes the case to a
collections officer (hardship, final stage, past grace). One open per due.
| Option | Fields / rule | What happens |
|---|---|---|
| Agree a payment arrangement | Note (required); optional "Pay by" date, on or before the grace end | arrangement recorded on the due; automated reminders stay stopped → billing.hardship_resolved (arrangement) |
| Resume reminders | refused if the due is paid or no ladder step is left before the grace end | dunning restarts at the next ladder step; on that date the clock fires dunning.step_due → TurfAI billing_dun again |
| Close the case — no change to the policy | Note (required) | billing.hardship_resolved (closed); nothing changes |
Grace expired (grace_expiry) — raised by the clock the day after grace ends with the premium unpaid.
| Option | Rule | What happens |
|---|---|---|
| Lapse the policy | refused when the due has been paid meanwhile, or the policy is not in force / in grace / revived | policy lapsed as of the grace end (last covered day), due lapsed, open collections reviews for the due cancelled → policy.lapsed; open renewal touches are superseded |
| Close the case — no change to the policy | Note (required); only when the due is already paid | no event |
Billing check (billing_review) — raised when TurfAI's billing contract disagrees with the
insurer's recomputed facts (amount, grace end, due date, mandate validity, next dunning date, …) or the rail refused a
debit. The CRM already used the insurer's values. Option Acknowledge — records that you saw it; no event.
2.5 Collections & finance — "Reconciliation exception" (reconciliation_exception)
Raised by billing_reconcile for every feed line TurfAI flagged (TurfAI marks it "for review by finance"; the same
Collections & finance desk works it). Nothing is applied to a due until that decision.
Options are narrowed to the line's state:
| Option | Offered for | What happens |
|---|---|---|
| Collect the balance | short | part payment stays against the due, which stays open for the balance (collection / reminders carry on) |
| Write off the shortfall | short | Note (required); due settled with the part payment, shortfall written off → also payment.received |
| Apply to a premium due | unmatched (and held lines) | "Premium due id (the due you traced the remitter to)"; the due must be unpaid and its outstanding must equal the cash → due settled, payment.received |
| Refund | any | refund instruction RFND-<bank ref> for the excess (over) or the whole credit |
| Hold in suspense | over / duplicate / unmatched | Note (required); amount parked in premium suspense |
| Confirm the rail debit | held lines whose debit reference names a rail debit for the same amount still awaiting bank confirmation | the rail payment is marked bank-confirmed and the held entry merged into it |
Every decision emits reconciliation.resolved. A line whose figures the insurer could not reproduce is held
(cash recorded unapplied) with the differences listed.
2.6 Relationship manager — "Renewal hand-off" (renewal_handoff)
Raised by renewal_action for every renewal (cadence) or retention (lapse-risk) touch TurfAI hands off, unless TurfAI
stops the cadence. The task shows TurfAI's priority, outreach draft, channel, cross-sell and System checks.
| Option | Rule | What happens |
|---|---|---|
| Send TurfAI's draft | only offered when TurfAI's channel is one the customer consented to; refused if the customer opted out of renewal contact | the draft goes out exactly as written; your optional note travels beside it → renewal.outreach_sent + customer Renewal / retention offer on portal Offers |
| Record the outcome | Outcome: Renewed — premium paid · Will pay before the deadline · Payment arrangement discussed (collections officer decides) · Will revive after lapse · Customer declined · No response · Not contactable | touch closed → renewal.outcome; an unanswered customer offer is cancelled |
| Withhold (do not send) | "Why it is withheld (required)" | nothing sent → renewal.outcome (withheld) |
When the customer answers the offer, a follow-up hand-off arrives with only Record the outcome. A touch is closed automatically (superseded, tasks cancelled) when the premium is collected / paid, or the policy lapses or is revived. Renewals never change billing or policy status. At Semi-auto or above the autopilot sends TurfAI's draft itself when the hand-off is sendable, not escalated, addressed to the RM (not a broker), the cadence is not stopped and System checks found 0 mismatches (§1.8); follow-ups always wait for the RM.
2.7 Claims officer
Claim triage (claim_triage) — two forms:
- Triage exception (gate): TurfAI held the claim, asked for requirements, flagged a duplicate / beneficiary /
screening issue, did not register it, or the insurer's recomputed facts disagree. Claim status
triage_review. Owned by Compliance instead when TurfAI routes it to the compliance officer (AML / PEP / sanctions hit). The task carries the insurer's other claims on the policy (insurer_open_claims/insurer_settled_claims: status, date of death, claimant, reported on, net payable and TurfAI's settlement recommendation when known), and its title names a possible duplicate first — "Triage exception — <name> · possible duplicate of CLM-… (status)" — whether TurfAI named it or only the insurer's records show it open. A report on a policy where a claim is already settled always comes here, even when TurfAI's routing is clean (TurfAI is only sent the open claims): title "possible duplicate of settled claim CLM-… (Settled)", hold reason "… — on the insurer’s claims records; TurfAI checks open claims only"; it can be registered (with the note), sent for documents, or linked as a duplicate of the settled claim (the officer's decision on the insurer's records — TurfAI's INT-5 is unchanged). - Notice: TurfAI registered the claim on a non-clean route —
investigate("Early claim registered with fraud priority") oradjudicate("Claim registered for adjudication (not in force on the date of death)"). Fraud scoring and settlement already started.
| Option | Offered | What happens |
|---|---|---|
| Register the claim | triage exception | claim registered → claim.triage_confirmed + claim.registered → fraud scoring and settlement start. When another claim on the policy is open or settled, the form warns (box "Another claim on this policy") "Another claim on this policy is open: CLM-… (status) — say why it is a separate claim." (for a settled one: "Another claim on this policy was settled: CLM-… — say why it is a separate claim.") and the note Why it is a separate claim (required) is required; the claims recorded are kept as registered_despite_open_claim on the change log and the event |
| Ask for documents | triage exception | "Documents still needed — shown to the nominee (required)" → claim requirements_pending; portal "More documents needed" with your note, TurfAI's outstanding documents and an Add documents form. When the nominee adds them (same claim reference, document ids continue the claim's sequence): claim back to intimated → claim.documents_received → TurfAI claim_intake re-runs with all the claim's documents and re-triages it — registered (fraud ∥ settlement start) or a new Claim triage task; the acknowledgement letter is replaced. No second claim is created (§3.4) |
| Link as duplicate | when TurfAI's routing names the insurer's claims records show another claim on the policy |
"Other claims on this policy" (box at the top of the triage drawer; chip Other claims). Display only — the duplicate judgement stays TurfAI's (INT-5); the box puts the insurer's own claims records beside it:
- read from the claims table when the drawer opens (not as at the task was raised): one row per other claim on the policy that is open or settled now: reference (→ its Policy 360), current status, Date of death, Claimant, Reported on, TurfAI recommends / Decision and Net payable when known, a TurfAI's duplicate badge on the claim TurfAI linked, and Open its task when that claim has an open task (e.g. its Settlement sign-off).
- a claim the task named when it was raised (or TurfAI's
duplicate_of) that is no longer open or settled: a row with its status now and "no longer open — not a claim to link to (was … when this task was raised)"; a TurfAIduplicate_ofthe insurer has no claim for on this policy: "Not on this policy’s claims records". When the records changed since, a line "Shown as the claims records are now. When this task was raised they showed: …". - TurfAI linked the claim: "TurfAI linked this claim as a duplicate of CLM-…" followed by its INT-5 detail.
- The insurer's records show an open claim but TurfAI's
duplicate_ofis empty: a red warning "The insurer's records show an open claim on this policy — TurfAI did not link it." with TurfAI's own words underneath, verbatim (the INT-5 check detail, a failed INT-2 check, triage reasons citing a duplicate — e.g. a different date of death on the certificate), or "TurfAI gave no reason on its duplicate check.", then "Compare the claims below before you decide." - The Register the claim warning and the link targets use the same live list.
- The Claim block's Duplicate of shows both values: "TurfAI <ref | —> · insurer <refs | —>" (e.g. "TurfAI — · insurer CLM-2026-000311").
On a Settlement sign-off the same box appears when another claim on the policy exists, read live from the claims table: an open one adds "Another claim on this policy is open — check it is not the same death before you sign this one off."; claims already closed as duplicates of this one are listed as "CLM-…-2 · closed as a duplicate of this claim". At Autonomous such a sign-off is never auto-approved: the autopilot's check "other claim on the policy: CLM-… (status)" fails and the card says it was left to you (§1.8).
Settlement sign-off (claim_signoff) — raised by claim_settle with TurfAI's recommendation (decision,
valuation lines, letter, compliance checklist), the insurer's own figures and the claim's TAT clock
(§3.7). Due on the clock start + 15 days (45 when investigation is
required) — the clock start is the last document's date, not the intimation. Three options — the officer approves or
overrides, always:
| Option | Note | What happens |
|---|---|---|
| Sign off TurfAI's recommendation | optional | signs off whatever TurfAI recommended (table below). The form states Written to the claim: ₹… (TurfAI's routing.net_payable — the figure written to the claim); when the insurer's recomputed net payable differs, a red line beside it: "The insurer's recomputed net payable is ₹… (policy admin + billing) — TurfAI's figure is the one written." Under it the penal interest: "Penal interest: none — Day 9 of 15 · 6 days left." or, once the clock is breached, "Penal interest due with the payment: ₹… — Breached by N days (…); (bank rate + 2 %) × the written amount × N days / 365, recorded with the sign-off." When the task carries System-check mismatches, a red box lists them (fact: TurfAI x, insurer y) with the checkbox "I have checked the N system-check mismatches and sign off TurfAI's figures anyway (required)" — the server refuses an approve with mismatches without it, and records acknowledged_mismatches |
| Ask for documents | "Documents the nominee must send — shown on the portal (required)" | overrides TurfAI: claim settlement_requirements (decision requirements) → claim.settlement_requirements. Nothing is paid and TurfAI's settlement letter is not sent; the portal shows your note ("More documents needed") with Add documents. When the nominee adds them: claim under_assessment → claim.settlement_reassess (documents_received) → TurfAI claim_settle re-runs with all the claim's documents → a new sign-off. The TAT clock is paused meanwhile and restarts from the last document |
Every option records the actor and the note on the change log and the event. Sign off TurfAI's recommendation does:
| TurfAI decision | After sign-off |
|---|---|
| admit · admit with rider · partial (suicide clause) | claim settled for the net payable → claim.approved; settlement letter + discharge voucher filed for the nominee; policy claimed, mandate cancelled, unpaid dues cancelled |
| repudiate | claim repudiated → claim.repudiated; decision letter with grievance rights filed for the nominee; policy terminated, mandate cancelled, unpaid dues cancelled |
| requirements | claim settlement_requirements → claim.settlement_requirements (requirements letter); the nominee answers with Add documents → settlement re-runs |
| investigate | never approvable — "Settlement held — awaiting the fraud outcome"; settlement re-runs when fraud clears or SIU grounds arrive |
The sign-off is held (the options are disabled, a "Sign-off held" box explains why) by settlementSignoffHold:
| TurfAI decision | Held while fraud status is | Released by |
|---|---|---|
| admit / admit with rider / partial suicide clause | anything except cleared · unsubstantiated · released | fraud.cleared (fraud score clear, SIU screen clear, unsubstantiated or released disposition) |
| repudiate | pending · referred · under investigation · inconclusive | a decided fraud outcome |
| requirements | never held | — |
| investigate | always | a new settlement run |
A held sign-off refuses every option (Ask for documents and Return for re-assessment too) — Fraud & SIU clearing releases it. A newer settlement run cancels the open sign-off ("a newer settlement assessment … superseded this sign-off").
At Autonomous the autopilot signs off a clean paying recommendation itself — admit / rider / partial, Fraud &
SIU cleared, not an early claim, not provisional, no investigation required, TurfAI's compliance sign-off passed, net
payable within the pay-out limit, not held, 0 System-check mismatches (§1.8). A held sign-off is re-evaluated when
fraud.cleared releases it. Repudiations, requirements and anything above the limit always wait for the officer. The
autopilot only ever uses Sign off TurfAI's recommendation — never Ask for documents or Return for re-assessment.
2.8 SIU lead — "SIU screen" (siu_screen)
Raised when fraud_score puts the claim in the medium band (human_review), or TurfAI said clear but the
insurer's recompute disagreed.
| Option | Field | What happens |
|---|---|---|
| Clear the claim | "Screening note — why the claim is cleared (required)" | fraud status cleared → fraud.screen_decided + fraud.cleared: the held sign-off is released, or settlement re-runs after investigate |
| Refer to SIU investigation | "Referral note for the investigator (required)" | SIU case SIU-<yr>-<n6> opened, fraud status referred → fraud.referred → SIU investigator task; settlement stays held |
2.9 SIU investigator — "SIU investigation" (siu_investigation)
Raised on fraud.referred (from fraud_score high band or an SIU screen referral), and again when the SIU lead
extends or returns the case. One option, Submit findings:
- "Findings document (.txt, required)", "Evidence uploads (.txt, optional, up to 5)" — plain text, ≤ 50,000 characters each; tick the claim / proposal documents relied on; optional "Note to the SIU lead".
- Files the findings and evidence on the case → case
findings_submitted→siu.findings_submitted→ TurfAIfraud_disposedrafts the disposition.
The findings document must end with a line that starts Investigator conclusion: followed by SUBSTANTIATED,
UNSUBSTANTIATED or INCONCLUSIVE (the disposition rule FDR-1: the human conclusion governs). Recommended shape —
numbered lines TurfAI can cite, then the conclusion (the B set Findings: non-disclosure substantiated under
Use sample documents — §1.9; file turfai/fixtures/fraud_dispose/docs/b_siu_findings.txt,
abridged):
TURFLIFE SIU — INVESTIGATOR FINDINGS, CASE SIU-2026-000877 (claim CLM-2026-000877, policy POL-LIFE-2025-000877)
Submitted by: SIU investigator; submitted on 18-11-2026
F1 Policy record verified: risk commencement 10-09-2025, no revival, 14 monthly premiums paid by NACH. Death on 03-11-2026 is 13.8 months after risk commencement.
F2 Cause of death verified with the treating cardiologist: acute anterior wall STEMI; death natural.
F3 Treating physician's statement: under his care from 14-03-2020 for essential hypertension and type 2 diabetes, continuous medication.
F6 Proposal (signed 02-09-2025): C7 chronic illness "No", C12 current medication "No".
F8 Medical officer opinion: the conditions were material to the risk; disclosure would have required an APS and a rated acceptance.
Investigator conclusion: SUBSTANTIATED — material non-disclosure at proposal. Recommend that repudiation grounds under section 45 be passed to Claims Settlement for its decision.
Other examples: Findings without a conclusion line (C8) (B) and Findings: inconclusive, enquiries open (the
background claim CLM-2026-001007) under Use sample documents; s5_siu_findings.txt (UNSUBSTANTIATED) is only in the
repo folder (not offered — §1.9). Without an explicit conclusion line (or with one that contradicts the findings)
TurfAI returns no outcome and the lead can only return the case. Each sample file has a Download link to edit it
and upload your own version.
2.10 SIU lead — "SIU disposition sign-off" (siu_disposition)
Raised by fraud_dispose with TurfAI's disposition (outcome, basis, per-indicator findings, s.45 repudiation grounds,
underwriting feedback). Due 2 days after the draft. Options depend on TurfAI's outcome:
| TurfAI outcome | Options offered |
|---|---|
| substantiated / unsubstantiated | Sign off TurfAI's disposition · Return to the investigator |
| inconclusive | Release to settlement · Extend the investigation · Return to the investigator |
| no conclusion | Return to the investigator only |
| Option | Note | What happens |
|---|---|---|
| Sign off TurfAI's disposition | optional | case closed with the outcome; claim fraud status = outcome → fraud.disposition. Substantiated: settlement re-runs with the repudiation grounds; TurfAI's underwriting feedback item is filed for Underwriting. Unsubstantiated: also fraud.cleared |
| Release to settlement | required | (inconclusive only) fraud status released → fraud.disposition + fraud.cleared |
| Extend the investigation | required | case extended → siu.investigation_extended → new investigator task (due on TurfAI's extend-until date) with the open lines |
| Return to the investigator | required | case returned → siu.findings_returned → new investigator task (due in 7 days) with your note; no conclusion recorded |
(Return / Extend failed with "The task could not be updated" before P12.8; fixed.)
At Autonomous the autopilot signs off an unsubstantiated disposition itself (sign-off offered, 0 System-check mismatches — §1.8); substantiated, inconclusive and no-conclusion drafts always wait for the SIU lead.
2.11 Complaint owner (grievance officer)
Complaint acknowledgement (complaint_acknowledgement) — raised when TurfAI says an acknowledgement is required.
Option Send TurfAI's acknowledgement: sends TurfAI's draft verbatim, DL-ACK met today, you become the case owner,
status acknowledged → complaint.acknowledged + a Complaint resolution task. Refused if a newer TurfAI run
superseded the task. Also allowed on a case escalated before its acknowledgement went out (then no resolution task —
the escalation task carries the case). At Semi-auto or above the autopilot sends the acknowledgement itself when
TurfAI requires one, asks for no human review, did not escalate, drafted the text, and System checks found 0
mismatches (§1.8); the resolution task then arrives with no owner yet — the
complaint owner who works it becomes the owner.
Complaint resolution (complaint_resolution) — raised after the acknowledgement (or directly when none is
required); due on the primary clock.
| Option | Fields | What happens |
|---|---|---|
| Record the resolution | "Decision on the complaint": Decision upheld, with reasons · Decision reversed · Partly reversed · Explained / information given; "Written response sent to the complainant (required)" | status resolved, primary clock met → complaint.resolved → TurfAI re-checks the case (within TAT). The complainant sees your response verbatim. Every other open case task is cancelled |
| Add a case note | "Case note (required)" | note on the case → complaint.note_added; the same task comes back |
The pack never resolves a complaint — only this human decision does.
2.12 Compliance & grievance — "Complaint escalation" (complaint_escalation)
Raised when TurfAI's at-risk re-check escalates the case before the breach; it supersedes the owner's resolution task. Always lands with the Compliance & grievance desk; the task title, case panel and portal note name whoever TurfAI escalated to (Head of Grievance Redressal, Head of Compliance, the owner's team lead). Same two options as Complaint resolution (Record the resolution, Add a case note).
2.13 Compliance & grievance — the other tasks
- Claim triage on a screening hit (see §2.7).
- Complaint escalation (§2.12).
- Regulator notice sign-off (
complaint_notice_signoff) — raised when TurfAI drafted a regulator / Ombudsman notice. Option Sign off TurfAI's notice draft (optional note): the draft is signed off verbatim →notice.signed_off. Filing it is outside the demo; Compliance cannot return a draft (K16).
2.14 System (ops) — "System — run failure" (system)
Raised when a TurfAI run still failed after its one automatic re-trigger (invalid contract or failed run), or when writing a valid contract into the CRM failed.
| Option | What happens |
|---|---|
| Retry | mapper failure → the same valid run is mapped again; otherwise a fresh TurfAI run with the same inputs (same as-of date) |
| Dismiss | closes the task; nothing else |
3. End-to-end flows
Legend for the step tables: Who = portal persona, console role or system (worker / clock / mock); TurfAI = the workflow that runs (40–250 s); Event = the outbox event that moves the flow on.
3.1 New business: apply → underwriting → issuance
flowchart TD A[Customer: Apply or New customer sign-up] -->|proposal.submitted| UW[TurfAI uw_assess] UW --> M[Underwriter: Underwriting memo] UW -->|Semi-auto or above, clean standard memo, 0 mismatches| AP[Autopilot: Accept standard] AP --> PI[TurfAI policy_issue] M -->|Accept standard| PI M -->|Rated / exclusion or Counter-offer| CO[Customer: Counter-offer on Offers] M -->|Decline| DEC[Proposal declined] M -->|Request requirements| RQ[Customer: Apply - Send to underwriting] RQ -->|proposal.requirements_submitted| UW CO -->|Accept| PI CO -->|Decline| OD[Offer declined - end] PI -->|clean, in force| ISS[Policy issued - mandate, schedule, documents] PI -->|non_standard or mismatch| IR[Servicing officer: Issuance review] PI -->|pending_first_premium| PFP[Proposal waits for first premium] IR -->|Confirm issuance| ISS IR -->|Reject| REJ[Issuance rejected - end]
| # | Who | What | TurfAI | Event | Result |
|---|---|---|---|---|---|
| 1a | Portal persona (A1 / R1) | Apply: pre-filled draft; tick the documents on file to send and / or upload; optionally Pay the first premium now (₹…); accept the declaration; Submit application | — | proposal.submitted | proposal submitted; AML screening of the applicant (mock) |
| 1b | New customer | Act as → New customer… → "Your details" (Fill sample details for a fictional applicant) → Sign up and start my application → Apply. Unanswered health questions show as "Choose…" | — | — | customer CUST-9NNNNN, draft PRP-<year>-9NNNNN, mandate request |
| 1c | Portal | Documents: plain-text uploads only; choose what each file is; No files? Use a demo sample written from your details: KYC, ITR / Form 16, Medical exam report, Lab report (labelled "Demo sample text"). If no proposal form is sent, one is generated from the answers | — |
Policy numbers: A1 POL-LIFE-2026-000101, R1 POL-LIFE-2026-000102, sign-ups POL-LIFE-<year>-9NNNNN. Risk
commences on the issue date; free-look end = RCD + 30 days; next due = RCD + one premium period.
What TurfAI's rules imply (manual turfai/fixtures/reference/uw_manual.json):
- UWM-10 KYC in all cases: no KYC document (Aadhaar / PAN) on file →
requirements(a clear AML screening does not replace it). With a UWM-9 referral the referral stays and KYC is listed outstanding. - UWM-11 every requirement is
satisfied,outstandingornot_required(a requirement whose trigger does not apply is never "satisfied"). - UWM-2 non-medical limits (inclusive): age 18–35 ₹1,00,00,000 · 36–45 ₹40,00,000 · 46–55 ₹20,00,000 · 56–65 none. Above → medical examination + lab panel required.
- UWM-7 financial proof: sum proposed above ₹50,00,000 → latest 2 years' ITR / Form 16. Justified sum = income multiple (25 / 20 / 15 / 10 by age band) × annual income; aggregate cover above it = over-insurance → counter-offer or more proof.
- UWM-1 rating starts at 100 %; loading = total − 100 rounded up to 25; 101–150 mild, 151–250 substandard. UWM-9 suspected non-disclosure → refer to the medical underwriter, never standard. UWM-8 aggregate above ₹2,00,00,000 retention → reinsurance referral.
refer and postpone recommendations have no matching button: the underwriter picks the decision (a TurfAI
requirements letter can go with Request requirements on a refer).
3.2 Billing: collection, dunning, grace, lapse, reconciliation
flowchart TD D[Clock: premium.due] --> BC[TurfAI billing_collect] BC -->|debit| RAIL[Mock rail presents the debit] BC -->|block_remandate| F1[collection.failed - mandate blocked] RAIL -->|success| OK[Due collected] RAIL -->|failed| F2[collection.failed] F1 --> DUN[TurfAI billing_dun] F2 --> DUN DUN -->|next step on ladder| STEP[Clock: dunning.step_due - retry or reminder] STEP --> DUN DUN -->|human_route| CR[Collections & finance: Collections review] DUN -->|lapse_risk_signal| LR[billing.lapse_risk to TurfAI renewal_action] H[Customer: I'm having difficulty paying] --> DUN P[Customer: Pay now] -->|payment.received| DUN GE[Clock: grace expired, unpaid] --> GX[Collections & finance: Grace expired] GX -->|Lapse the policy| LAP[Policy lapsed] FEED[Clock: settlement_feed.arrived] --> REC[TurfAI billing_reconcile] REC -->|matched| SET[Due settled / bank-confirmed] REC -->|short / over / duplicate / unmatched| FX[Collections & finance: Reconciliation exception]
| # | Who | What | TurfAI | Event | Result |
|---|---|---|---|---|---|
| 1 | Clock | premium due date reached (persona policies only, by default) | billing_collect | premium.due | TurfAI bills the instalment and instructs debit or block_remandate |
| 2 | Mock rail | presents the debit only if the contract is valid and the mandate is valid (active, not expired, same policy). Outcome is scenario-driven: only C's 2026-11-15 attempts 1 and 2 fail (insufficient funds); everything else succeeds | — | collection.succeeded / collection.failed | success → due collected, payment row; failure → dunning |
| 3 | system | mandate blocked (missing / expired / inactive / mismatch) | — | collection.failed (mandate_blocked) | dunning stage 0 with the re-mandate path; Payments pre-selects |
Any disagreement between a billing contract and the insurer's recompute → Billing check (billing_review); the
CRM keeps the insurer's values.
3.3 Renewals / retention and servicing
Renewals / retention
| # | Who | What | TurfAI | Event | Result |
|---|---|---|---|---|---|
| 1 | Clock | renewal window opens (monthly: within 7 days of every due — so persona policies get a touch each month, e.g. A1 from 2026-11-24 for the 12-01 due) | renewal_action (cadence) | renewal.window_open | renewal_actions row; unless TurfAI stops the cadence → RM Renewal hand-off |
| 1b | system | lapse-risk signal from dunning | renewal_action (lapse_risk, with the lapse context) | billing.lapse_risk | retention hand-off, due by the lapse deadline (grace end) |
| 2 | RM | Send TurfAI's draft / Record the outcome / Withhold (do not send) | — | renewal.outreach_sent / renewal.outcome | customer offer on portal Offers (when sent) |
A newer touch on the same policy supersedes an older one still open.
Servicing (portal Ask about my policy)
Pick the Policy and What do you need? — A question about my policy · Change my details or nominee
(endorsement) · A premium-paid certificate · Return my policy in the free-look period · Revive a lapsed policy —
fill the fields (for an endorsement What to change: Nominee · Address · Phone / e-mail · How often I pay (premium
mode); nominee shares must total 100 %; a certificate asks the Financial year), optionally attach your documents
→ Ask / Send request. Event servicing.requested → TurfAI policy_service (Request Resolver, then the Q&A
agent or the Endorsement & Service agent).
| TurfAI result | App does | Human task |
|---|---|---|
| answered (question) | answer with clause citations on the Ask page | — |
| generated (certificate) | certificate stored as a policy document (held if its totals disagree with the billing schedule) | Servicing escalation if held |
| applied / drafted with a record action (nominee, address, contact, premium mode, free-look cancellation) | change written; confirmation stored as a policy document | Servicing escalation if the CRM cannot write it or values disagree |
| declined (out of scope) | — | Servicing escalation: Reply / Decline |
| held (other) | — | Servicing escalation: Apply the change (when allowed) / Reply / Decline |
| held, revival (always) | — | Revival request |
Premium-mode changes are recorded but not applied at the anniversary; a free-look refund is recorded without a finance approval / payout (K16).
Revival (C's 2027 beat):
| # | Who | What | TurfAI | Event | Result |
|---|---|---|---|---|---|
| 1 | Customer | Payments on a lapsed policy → Ask to revive this policy (opens Ask with Revive a lapsed policy); attach the health declaration file (C has revival_health_declaration.txt; "A revival needs a declaration of good health") → Send request | policy_service | servicing.requested | mock billing produces the revival quote (arrears + 9 % p.a. simple interest, valid 5 days); TurfAI restates it and holds the request |
| 2 | Servicing officer | Revival request → Approve the revival / Decline the revival | — | servicing.revival_approved / servicing.resolved | customer Revival payment |
| 3 | Customer | Payments → Pay ₹8,485 and revive (C on 2027-01-10) | — | policy.revived | arrears dues collected, policy , last revival date set (contestability re-opens from it), billing resumes |
3.4 Claims: intake → fraud ∥ settlement → SIU → sign-off
flowchart TD R[Nominee: Report a claim] -->|claim.intimated| CI[TurfAI claim_intake] CI -->|fast_track, clean| REG[Registered] CI -->|investigate / adjudicate, clean| REGN[Registered + Claim triage notice] CI -->|hold / requirements / duplicate / screening / mismatch / claim already settled on the policy| TR[Claims officer or Compliance: Claim triage] TR -->|Register the claim| REG TR -->|Ask for documents| RP[Documents requested - clock paused] RP -->|Nominee: Add documents - same claim, claim.documents_received| CI TR -->|Link as duplicate - TurfAI or an open / settled claim on the insurer records| DUP[Duplicate - closed] REGN --> REG REG -->|claim.registered| FS[TurfAI fraud_score] REG -->|claim.registered| CS[TurfAI claim_settle] FS -->|low: clear| FC[fraud.cleared] FS -->|medium: human_review| SC[SIU lead: SIU screen] FS -->|high: refer| SIU[SIU case + SIU investigator task] SC -->|Clear the claim| FC SC -->|Refer to SIU investigation| SIU SIU -->|Submit findings| FD[TurfAI fraud_dispose] FD --> LEAD[SIU lead: SIU disposition sign-off] LEAD -->|Return / Extend| SIU LEAD -->|Sign off unsubstantiated / Release| FC LEAD -->|Sign off substantiated| GR[fraud.disposition with s.45 grounds] GR --> CS CS --> SO[Claims officer: Settlement sign-off] FC -->|releases hold / re-runs settlement after investigate| SO SO -->|Sign off: admit| ST[Settled - policy claimed] SO -->|Sign off: repudiate| RE[Repudiated - policy terminated] SO -->|Sign off: requirements, or Ask for documents| SR[Documents requested for settlement - clock paused] SR -->|Nominee: Add documents - same claim, claim.settlement_reassess| CS SO -->|Return for re-assessment - note as officer_review| CS
The documents loop (P16.2). A claim waiting for documents is never re-reported: the nominee adds them to the
same claim on the portal (Add documents on the claim card), and TurfAI is re-triggered with what changed —
asked at triage (requirements_pending) → claim_intake re-runs (registered, or a new Claim triage task); asked at
settlement (settlement_requirements, by TurfAI's requirements decision or the officer's Ask for documents) →
claim_settle re-runs (a new Settlement sign-off). Any other status refuses the form ("Documents not added"); a double
submit files nothing twice. The TAT clock is paused while documents are requested and restarts from the last document
(§3.7).
| # | Who | What | TurfAI | Event | Result |
|---|---|---|---|---|---|
| 1 | Portal (the policyholder persona; the nominee acts once the death is known) | Report a claim → "Report a death" (while a claim on the policy is not closed: the notice "You already have claim CLM-… (…) on this policy — its progress is shown above" and Report this death again to unfold the form; refused only while the first claim is still "Received", C4): Policy, Name of the insured, Date of death, Cause of death, Place of death, claimant name / relationship / e-mail / phone, optional intimation e-mail text, plain-text documents (choose each kind: claim form, death certificate, your ID, bank proof, medical attendant's certificate, hospital summary, …) — or Use sample documents for the persona's storyline set (§1.9; the fields open pre-filled from the persona's sample claim form) → Submit claim | — | claim.intimated | claim CLM-<year>-<policy n6> (-2, -3 for later ones), status intimated; claimant screened (mock AML); customer marked deceased |
| 2 | system | intake | claim_intake | acknowledgement letter filed for the nominee; routing below |
Valuation (checked by the insurer): gross = sum assured + bonuses on file; deductions = policy loan principal + interest to the date of death + the premium unpaid in grace on the date of death; on an s.45 non-disclosure repudiation the premiums received are refunded (s.45(4)). Sign-off due: 15 days from the clock start (the last document's date, else the intimation), 45 days when investigation is required — §3.7.
3.5 Complaints
flowchart TD C[Customer / nominee: Raise a complaint] -->|complaint.raised| H1[TurfAI complaint_handle mode new] H1 -->|acknowledgement required| ACK[Complaint owner: Complaint acknowledgement] H1 -->|none required| RES[Complaint owner: Complaint resolution] H1 -->|notice drafted| NS[Compliance: Regulator notice sign-off] ACK -->|Send TurfAI's acknowledgement| RES RES -->|Add a case note| RES CLK[Clock: escalation trigger day 10] -->|complaint.at_risk| H2[TurfAI complaint_handle mode at_risk] H2 -->|escalate| ESC[Compliance & grievance: Complaint escalation] RES -->|Record the resolution| DONE[Resolved] ESC -->|Record the resolution| DONE DONE -->|complaint.resolved| H3[TurfAI re-check: within TAT]
| # | Who | What | TurfAI | Event | Result |
|---|---|---|---|---|---|
| 1 | Portal | Raise a complaint → "What is it about?" (Claim rejected · Claim delayed or unanswered · Premium, payment or refund · Policy service (documents, changes, no reply) · Policy sold to me wrongly · Something else), About (policy / claim), Subject, What happened?, What would you like us to do?, name, relationship, contact → Raise complaint. One open complaint per claim / policy at a time | — | complaint.raised | status "Received — being registered" |
| 2 | system | classify (grievance or query, category, severity), set clocks DL-ACK (3 days) / DL-GRV (14 days) / DL-OMB, open the case, route it, draft the acknowledgement, regulator notice if needed | complaint_handle (new) | Complaint acknowledgement (or Complaint resolution); Regulator notice sign-off when a notice is drafted | |
| 3 | Complaint owner | Send TurfAI's acknowledgement | — | complaint.acknowledged | DL-ACK met; owner assigned; Complaint resolution |
There is no console capture form for contact-centre complaints and no breach-date re-check (K16).
3.6 Showing the autonomy ladder
The demo script for the autonomy level (§1.8): the same Loop 1 twice — once with the underwriter in the loop, once with the autopilot — and back. Start from Reset demo (level HITL); the clock stays on 2026-11-01 throughout. Three TurfAI runs (steps 1, 4 and 7 — ≈ 1–4 min each); nothing else costs tokens.
| # | Who | What | TurfAI | Event | Result |
|---|---|---|---|---|---|
| 1 | A1 (portal) → Underwriter | §3.1 steps 1a–3a at HITL: Arjun applies (pay the first premium now); the memo lands in the Underwriter inbox — open it: badge Your call, the sticky Decide: bar; Accept (standard) → Submit | uw_assess, then policy_issue | uw.approved (source human:underwriter, actor underwriter:console.demo) | POL-LIFE-2026-000101 in force. Point out: the human gate, the frame badge Autonomy: HITL |
| 2 | Console → Clock | Autonomy level card → Semi-auto → Save autonomy level | — | — | "Autonomy: Semi-auto · pay-out limit ₹50,00,000 — Saved …"; the frame badge reads Autonomy: Semi-auto; the demo.settings change is logged |
| 3 | New customer (portal) | → → → : keep the defaults (TL-SECURE-TERM, ₹50,00,000, 25 years, monthly), for (the sample applicants are 29–38, so no medicals or ITR are required under UWM-2 / UWM-7), optionally , accept the declaration, |
If TurfAI's memo for the sign-up is not clean — e.g. compliance_pass: false, a requirement listed outstanding, a
refer, or a System-check mismatch (K18 variance) — the autopilot leaves it for the underwriter exactly as at HITL; the
Decision card opens with "Left to you by the autopilot (Semi-auto): …" naming the failing check(s) (the stamp
autopilot.eligible: false is in the drawer's Payload). Say so and decide it by hand; the ladder is about clean
cases.
Autonomous is demo only. The ladder is shown at Semi-auto; if you go on to Autonomous, say what the amber note on the card and the storyline panel says: the specs have a claims officer approve every claim, so Autonomous exists to show the autopilot's checks, not as a mode an insurer would run. Even there it never repudiates (only a paying decision qualifies), never signs a substantiated fraud case (only an unsubstantiated SIU disposition) and never pays above the pay-out limit.
Rehearsal without TurfAI (recorded contracts, worker allowed to run): npm run demo:reset → set the level on the
Clock page → npm run replay:a1-autopilot -w @uip/worker. At Semi-auto / Autonomous it prints "POL-LIFE-2026-000101
issued by the autopilot" and steps 5–6 can be shown on Arjun's memo (Auto-approved share 1 of 1); at HITL it prints
"memo left open" and the memo waits in the Underwriter inbox. demo:reset afterwards (the setting goes with it).
3.7 The claim TAT clock and penal interest
TurfAI's claim_settle computes the settlement clock on its recommendation (SET-11) and the penal interest (SET-9).
The insurer keeps the same clock itself (P16.4) — dates, a status and arithmetic, no judgement — recomputes TurfAI's
figures as System checks (compliance.tat_clock start / elapsed / days left / status / breached / delay,
valuation.penal_interest), and shows it in the console:
| Rule | Value |
|---|---|
| Clock start | the date the last claim document was filed (the insurer's own letters do not count), else the intimation date — the badge's tooltip says which ("(last document received)" / "(intimation — no document date on file)") |
| Applicable | 15 days; 45 days when investigation is required — an early claim (SET-3, within the contestability window per policy admin) or a Fraud & SIU referral (referred, under investigation, substantiated, unsubstantiated, inconclusive, released) |
| Paused | while documents are requested (requirements_pending, settlement_requirements): "Paused — documents requested (15-day clock)", no interest. Documents added restart it from the new last document |
| Running | elapsed = sim date − clock start; "Day 9 of 15 · 6 days left" |
| Stopped | at the decision (settled / repudiated, the decision date): badge "TAT 15d · Met" or "TAT 15d · Breached" |
| Status | green "On time" · amber "Due soon" (≤ 3 days left) · red "Breached" (elapsed > applicable: "Breached by 3 days (day 18 of 15)") · "Paused". A stopped clock is green or red, never amber |
| No clock | duplicate, withdrawn or closed claims |
| Penal interest | only when breached: (bank rate 6.75 % + 2 %) × the written amount (TurfAI's net payable) × delay days / 365, rounded to the rupee. The bank rate is SET-9 in the reference data |
Where it shows:
- Policy 360 — a TAT column on the claims table and the badge (status, days left / delay, penal interest, "from … · due …") on the claim block.
- Claim triage and Settlement sign-off drawers — the badge on the claim block; on the sign-off, the penal interest line under Written to the claim (§2.7).
- Dashboards → Claims Settlement — the Claims TAT tile: open claims on the clock with counts On time / Due soon / Breached / Paused, and "Penal interest accrued ₹…" on the breached ones whose current recommendation pays (not the indicative figure of a claim awaiting the fraud outcome).
Recorded at sign-off. Sign off TurfAI's recommendation records the clock (tat_clock, incl. delay_days) and,
on a paying decision, penal_interest_due — computed by the server at the sim date, not taken from the form — on the
claim's decision, the change log and the claim.approved event. Example (P16.4 check): A2's claim, clock start 11-02,
due 11-17, signed off with the clock at 11-20 → day 18 of 15, breached by 3 days → 8.75 % × ₹27,67,173 × 3 / 365 =
₹1,990. The sign-off due date on the task is clock start + 15 (or 45) days.
The dashboard's Decided within TAT metric uses the same clock: a decided claim counts as within TAT when the clock recorded at sign-off (else the claims system's stopped clock) met its 15 / 45 days — Median days to decision still counts intimation → decision.
To see the colours without a TurfAI run, replay a claim and advance the clock — but pause the worker first (§7.1).
4. Who approves what, when
"Autopilot from level" = the lowest autonomy level at which the orchestrator closes a clean instance of the gate itself by applying TurfAI's recommendation (§1.8); never = always a person, at every level.
| Decision | Role | Task kind (inbox label) | Triggered by | Options | Held / refused until | Emits → next | Autopilot from level (§1.8) |
|---|---|---|---|---|---|---|---|
| Underwriting decision | Underwriter | uw_memo (Underwriting memo) | every uw_assess result | Accept (standard) · Rated / exclusion · Counter-offer · Decline · Request requirements | terms must fit the option; decline needs a note | uw.approved → policy_issue (standard) / customer Counter-offer / requirements on Apply / end | Semi-auto — standard, no referral, no outstanding requirements, compliance pass, loading 0, no exclusions, no over-insurance, 0 mismatches → Accept (standard) |
| Accept revised terms | Customer (portal Offers) | counter_offer | underwriter Rated / Counter-offer | Accept · Decline | first premium must equal the quote (top-up allowed; overpayment refused) | uw.offer_accepted → · → end |
5. The TurfAI workflows
Thirteen activities named UIP · <pack> · <name> (12 pack workflows + smoke), defined in
turfai/src/workflows/*.ts. Every run receives request_id, as_of_date (sim date), market (INR, IN-IRDAI), the
relevant product_config slice and the insurer's rules as reference data with section ids (UWM-, BCR-, DGR-, REC-,
RNR-, SVR-, INT-, FRR-, FDR-, SET-, CMR-n) — so every judgement cites a rule. Documents travel as text; citations
are {doc_id, locator}. Data Shield (PII masking) is on for every LLM step. Judgement steps run on
gemini-2.5-pro, the rest on gemini-2.5-flash. A run typically takes 40–250 s (measured live: uw_assess 88–180 s,
policy_issue ~56 s); long underwriting and reconciliation batches take longer.
5.1 uw_assess — UIP · 3 Underwriting · Assess proposal
- Trigger:
proposal.submitted;proposal.requirements_submitted(same inputs, all documents sent so far). - Reads: the proposal (applicant, plan, sum, term, mode, disclosures, medical, financial), documents as text,
existing cover, the AML screening result, the underwriting manual (
uw_manual). - Steps: Submission Parser → Underwriting Analyst (pro) → Coverage-Gap Detector → Compliance Reviewer (pro) → Contract.
- Decides:
decision.typestandard · rated · exclusion · counter_offer · requirements · refer (senior / medical / reinsurer) · postpone · decline; rating factors and total rating %, loading, exclusions, requirements with satisfied / outstanding / not_required, reinsurance referral, compliance (incl. KYC ok / document_missing / hit), memo synthesis, one applicant letter (acceptance / counter_offer / requirements / decline / postpone). - Follow-up: Underwriting memo (always). Never binds cover.
5.2 policy_issue — UIP · 4 Issuance · Issue policy
- Trigger:
uw.approvedwith decision standard;uw.offer_accepted. - Reads: the approved recommendation and the underwriter's decision, the rating-engine quote, policy number from policy admin, nomination, mandate request, first-premium receipt.
- Steps: Policy Assembler (pro) → Contract(policy) → Certificate & Kit → Contract(documents).
- Decides: issued policy (status in_force / pending_first_premium,
non_standard+ review reasons), mandate, policy schedule and certificate text. - Follow-up: clean → policy issued automatically; non_standard or mismatch → Issuance review; pending_first_premium → proposal parked.
5.3 policy_service — UIP · 4 Servicing · Service policy request
- Trigger:
servicing.requested(portal Ask). - Reads: policy record, this policy's documents, product wording (clause ids), billing summary (so payment questions are grounded), servicing rules (SVR-n), the request and attachments, the revival quote for a revival.
- Steps: Request Resolver → branch "Question?" → Policy Q&A Agent (pro) or Endorsement & Service Agent (pro) → Contract(qna) / Contract(service).
- Decides: type qna / endorsement / certificate / free_look / revival; status answered / declined / applied / drafted / generated / held; record action (replace nomination, update address / contact, change premium mode, cancel free look).
- Follow-up: §3.3 table — Servicing escalation or Revival request when declined / held; revival is always held.
5.4 billing_collect — UIP · 8 Billing · Bill and collect premium
- Trigger:
premium.due(in scope);mandate.registeredwith an open due. - Reads: the due, mandate, policy, customer consent, billing rules (BCR-n).
- Steps: Billing & Invoicing Agent → Collection Agent (pro) → Contract(billing_event).
- Decides:
instructiondebit / block_remandate, block reason, re-mandate request. - Follow-up: the mock rail debits (or not); failure →
billing_dun; mismatch / rail refusal → Billing check. Never moves money itself.
5.5 billing_dun — UIP · 8 Billing · Dun failed premium
- Trigger:
collection.failed,dunning.step_due,customer.hardship_reported, and recovery events on a due already in dunning (collection.succeeded,payment.received). - Reads: the due with the collection attempts, dunning history, consent, hardship signals, dunning rules (DGR-n), the ladder and grace days.
- Steps: Dunning Agent (pro) → Contract(billing_event) → Dunning Communications → Contract(communications).
- Decides: status in_dunning / escalated / lapsed_risk / collected; stage; next action retry_debit / reminder / final_reminder / grace_end_review / none; hardship flag; human route (collections officer); lapse-risk signal; customer messages.
- Follow-up: Collections review when routed;
billing.lapse_risk→renewal_action. Never lapses a policy.
5.6 billing_reconcile — UIP · 8 Billing · Reconcile settlement feed
- Trigger:
settlement_feed.arrived(unless billing scopenone);settlement_feed.next_batch. - Reads: one feed batch (≤ 8 bank lines), open expected premiums, dues already settled, reconciliation rules.
- Steps: Reconciliation Agent (pro) → Contract(reconciliation).
- Decides: one item per line — match state matched / short / over / duplicate / unmatched, exception type (shortfall / unapplied / duplicate) flagged for finance.
- Follow-up: matched settles / bank-confirms; every flagged line → Reconciliation exception. Nothing flagged is applied.
5.7 renewal_action — UIP · 7 Renewals · Renewal / retention action
- Trigger:
renewal.window_open(cadence, in scope, due still scheduled);billing.lapse_risk(lapse_risk). - Reads: policy, holdings, consent, persistency history, trigger + lapse context, renewal rules (RNR-n), cross-sell catalogue, servicing roster.
- Steps: Renewal Detection & Timing → Renewal Analyst → Coverage-Gap & Cross-Sell (pro) → Outreach & Hand-off → Contract(renewal_action).
- Decides: window, priority (critical / high / medium / low), stop cadence, outreach draft + channel, hand-off (rm / broker), cross-sell.
- Follow-up: Renewal hand-off (unless stop cadence). Never prices, sends or closes.
5.8 claim_intake — UIP · 1 Claims Intake · Intake and triage death claim
- Trigger:
claim.intimated;claim.documents_received(the nominee added documents to a claim asked for them at triage — the same claim, re-run with all its documents, only while it is stillintimated). - Reads: the intimation and documents, the policy-admin record with billing facts for in-grace-on-date-of-death, the claims system's other open claims on the policy, the AML / PEP / sanctions result, intake rules (INT-n).
- Steps: Intake & Capture → Validation (pro) → Screening → Triage (pro) → Contract(claim_intake_record) → Acknowledgement Drafter → Contract(acknowledgement).
- Decides: validation (policy found, in force on the date of death with basis premium_paid / in_grace / lapsed / outside_term, completeness, claimant is nominee, duplicate), screening clear / hit / pending, triage decision fast_track / investigate / adjudicate / requirements / hold, route (claims_settlement / siu = fraud priority only / compliance / hold), early claim, acknowledgement letter.
- Follow-up: §3.4 step 2. Intake never refers to SIU and never rejects.
5.9 fraud_score — UIP · 5 Fraud · Score claim and refer
- Trigger:
claim.registered(every claim). - Reads: claim, policy record, the underwriting proposal and disclosures (+ any revival health declaration), claim and proposal documents, other cover on the life, agent / branch early-claim statistics, contestability parameters, fraud rubric (FRR-n).
- Steps: Fraud Scoring Agent (pro) → Referral / Triage Agent → Contract(fraud_assessment) → Contract(referral) → branch "Refer to SIU?" → SIU Case Agent → Contract(siu_case).
- Decides: six indicators — early_claim +3, health_habit_mismatch +3, financial_anomaly +2, document_forensics 2 / 3 / 5 (critical = showstopper), nominee_anomaly +1, agent_branch_cluster +2; score, band, recommendation clear / human_review / refer, SIU case stub and investigation plan. An isolated non-critical indicator never auto-refers.
- Follow-up: clear →
fraud.cleared; human_review → SIU screen; refer → SIU investigation. Never declares fraud.
5.10 fraud_dispose — UIP · 5 Fraud · Dispose SIU case
- Trigger:
siu.findings_submitted. - Reads: the SIU case and fraud assessment, the investigator's findings document and evidence, claim / policy facts for the s.45 window, original documents, disposition rules (FDR-n), fraud rubric, underwriting manual.
- Steps: Disposition Agent (pro) → Contract(disposition).
- Decides: outcome substantiated / unsubstantiated / inconclusive (or none), action repudiation_grounds / release, next step, per-indicator findings, s.45 repudiation grounds (material non-disclosure / fraudulent misstatement / document fraud), inconclusive next lines, underwriting feedback.
- Follow-up: SIU disposition sign-off (always needs the lead). Never repudiates.
5.11 claim_settle — UIP · 2 Claims Settlement · Settle death claim
- Trigger:
claim.registered(in parallel with fraud scoring);fraud.clearedwhen the last decision was investigate;claim.settlement_reassess(reasondocuments_receivedafter the nominee's Add documents, orofficer_returnafter Return for re-assessment);fraud.dispositionsubstantiated (with repudiation grounds). - Reads: the registered claim + intake contract, claim documents, policy record (bonuses, loan, unpaid in-grace
premium, premiums received), the current fraud status (never assumed clear), repudiation grounds, settlement rules
(SET-n, ADB-n),
last_document_date(the clock start), andofficer_review({note, returned_by, returned_on, previous_recommendation}on a re-run after the officer's return, null otherwise — TurfAI addresses the note in its synthesis but still applies the rules). - Steps: Evidence Collector → Coverage Analyst (pro) → Claims Valuator (pro) → Settlement Drafter (pro) → Contract(settlement_recommendation) → Compliance Reviewer (pro) → Contract(compliance_signoff).
- Decides: decision admit / admit_with_rider / partial_suicide_clause / repudiate (basis policy_not_in_force / s45_non_disclosure / s45_document_fraud / excluded_peril) / investigate / requirements; valuation; letter (discharge voucher / repudiation / requirements); TAT clock (15 / 45 days); compliance pass / kickback.
- Follow-up: Settlement sign-off. Only recommends — no auto-pay. The mapper recomputes the TAT clock and penal interest as System checks (§3.7).
5.12 complaint_handle — UIP · 6 Complaints · Complaint handling
- Trigger:
complaint.raised(mode new);complaint.at_risk(mode at_risk, on an open case with no run in flight);complaint.resolved(at_risk re-check). - Reads: the complaint, linked policy / claim / billing context, the existing case on a re-check, complaint rules (CMR-n, DL-ACK / DL-GRV / DL-OMB).
- Steps: branch "New complaint?" → Complaint Classification (pro) → Deadline & Case (pro) → Acknowledge & Routing → Regulatory Notice & Compliance (pro) → Contract(complaint_new); re-check path: Deadline & Case (re-check) → … → Contract(complaint_at_risk).
- Decides: grievance or query, category (claim_delay / claim_repudiation / mis_sale / servicing / premium / other), severity, deadlines and their states (on_track / at_risk / breached / met), case status, escalation, queue / owner, acknowledgement draft, regulator / Ombudsman notice draft, resolution within TAT, root-cause feedback area.
- Follow-up: §3.5. Never resolves.
5.13 smoke
A one-agent test workflow (policy status) used to prove trigger → LLM → contract → poll before the packs were built. Not used by the app.
5.14 System checks, lineage, Runs and retries
- System checks. Mappers recompute every deterministic fact they can from the CRM and product_config (ages, dates,
contestability anchor, grace on the date of death, premiums, valuation arithmetic, clocks, routing-field copies) and
list disagreements on the task: "System checks · N mismatches" —
fact: TurfAI x, insurer systems y, with the basis. The CRM always keeps the insurer's values. A mismatch never changes TurfAI's decision but it stops automatic steps: a claim is not auto-registered, a fraud "clear" goes to the SIU screen, an issuance goes to review, a certificate / change is held, a reconciliation line is held. - Lineage. Every task shows the TurfAI run (workflow, execution id, duration, contract valid / invalid — click it for the run page), the triggering event, and document chips for the documents TurfAI was actually given plus those it cited. Clicking a chip opens the document with the cited line highlighted. Clock / billing-raised tasks say "Raised by the insurer's systems (clock / billing scanner) — no TurfAI run involved".
- Runs page (
/console/runs): every execution with status (pending / triggered / queued / running / completed / failed …), "Contract valid" / "Contract invalid", mapped, attempt, duration, polls, token usage; filters All workflows / All statuses. A run's page shows "Inputs sent", the contract with "Validation errors", and "Raw execution outputs". Busy pages refresh every 3 s. - Retries. An invalid contract does not fail the TurfAI run, so the worker re-triggers once automatically; if the
retry is also invalid (or the run failed), a System — run failure task appears (Retry / Dismiss). TurfAI
occasionally returns invalid contracts (seen on
complaint_handle,claim_intake) and ~2 % of runs fail inside TurfAI ("LLM output format validation failed: expected json").claim_settlewith a failed compliance checklist is also re-triggered once. Stale results are ignored: a run older than the one already applied, or on a closed case, is recorded in history only.
6. Scenario catalogue
Start each block from a fresh Reset demo unless stated. "Expect" describes what the app does for sure, and what TurfAI is expected to return under its rules; TurfAI is an LLM, so its exact wording, and occasionally its judgement, varies (K18) — the human gate then decides.
6.1 Storyline beats (happy paths)
| # | Setup | Steps | Expected result |
|---|---|---|---|
| S1 | 11-01 | A1: Apply, keep KYC + ITR + proposal ticked, tick Pay the first premium now (₹1,404), declaration, Submit application | uw_assess run on Runs; memo "Recommend accept at standard rates"; requirements satisfied / not required |
| S2 | after S1 | Underwriter: open the memo, click a lineage chip, Accept (standard) → Submit | policy_issue; POL-LIFE-2026-000101 in force, nominee Divya Rao, mandate NACH-MND-88319 on My policy (or an Issuance review to confirm first) |
| S3 | after S2 | Clock → Advance to date 2026-12-01, then 2026-12-02 | 12-01 due collected (NACH-DEBIT-2026-120101); 12-02 feed line Matched on Policy 360 → Payments; background exception lines in the Collections & finance inbox |
| S4 | 11-01 | R1: Apply without paying; underwriter Rated / exclusion, Loading 50, no exclusions | Counter-offer on Kavya's Offers at ₹17,346 |
| S5 | after S4 | R1 Offers: → confirm |
6.2 Underwriting variations
| # | Setup | Steps | Expected result |
|---|---|---|---|
| U1 | A1, 11-01 | Untick the KYC document, submit | TurfAI requirements with KYC outstanding (UWM-10); memo pre-fills Request requirements |
| U2 | after U1 | Underwriter Request requirements (keep the pre-fill) → A1 Apply "More information needed": tick the KYC on file (or KYC sample) → Send to underwriting | uw_assess re-runs; new memo, KYC satisfied; standard |
| U3 | A1, 11-01 | Untick the ITR | requirements: financial proof (sum above ₹50,00,000) |
| U4 | New customer, age 36–45, sum assured ₹50,00,000, KYC sample only | Submit | requirements: medical exam + lab (above the ₹40,00,000 non-medical limit). Answer with Medical exam report + Lab report samples (clean values) → standard |
| U5 | New customer | Disclose a condition / treatment in the health questions (or upload evidence contradicting a "No") | rated or refer (UWM-4 debits / UWM-9 suspected non-disclosure → medical underwriter); possibly APS required |
| U6 | any memo |
6.3 Billing variations
| # | Setup | Steps | Expected result |
|---|---|---|---|
| B1 | C in dunning (after 11-15) | C: Pay ₹4,200 now | due paid, policy in force; dunning closes; renewal touch superseded |
| B2 | C hardship task | Agree a payment arrangement with Pay by after the grace end | refused ("a later date would need a revival") |
| B3 | C hardship task | Resume reminders after the last ladder step | refused ("no automated dunning step is left") |
| B4 | Grace expired task on a paid due | Lapse the policy | refused ("already paid — close the task") |
| B5 | 12-02 feed | Collections & finance: open each exception (short / over / duplicate / unmatched) and try each option | options narrowed per state; Apply to a premium due refused unless the due is unpaid and equals the amount |
| B6 | C | Re-register mandate while a due is open | billing_collect presents the due on the new mandate |
| B7 |
6.4 Claims variations and negative cases
| # | Setup | Steps | Expected result |
|---|---|---|---|
| C1 | A1 issued 11-01 (RCD 2026-11-01) | Report a death dated before 2026-11-01 | TurfAI intake: not in force (outside_term) → adjudicate. The insurer recompute agrees (P16.1: a death before the RCD is outside_term, checked first), so with no other mismatch the claim is registered for adjudication with a Claim triage notice (no validation.policy_in_force mismatch). Settlement is then expected to repudiate (policy not in force); its in-grace check reads the same cover (no premium deducted). Insurer side verified in unit tests; not re-run live |
| C2 | A2, 11-02 — instead of S6's clean claim, on a fresh demo:reset (reported after the clean claim it is the next row, C2a) | Acting as A2: Report a claim (fields pre-filled) → Use sample documents → Death certificate that does not match (C2) (or download the A2 death certificate, edit name / DOB / date and upload it; file fixtures/documents/samples/a2_death_certificate_mismatch.txt) | intake may hold / ask for documents (policy match, INT-2); if registered, fraud expected to find document_forensics (critical weight 5 → high) → refer to SIU |
| C2a | C2 after the clean claim — S6 done to "Assessed" (CLM-2026-000311 awaiting sign-off) | Acting as A2: Report a claim → Report this death again → Use sample documents → Death certificate that does not match (C2) → |
6.5 Complaints and servicing
| # | Setup | Steps | Expected result |
|---|---|---|---|
| K1 | any customer | Raise a complaint, then raise another about the same matter | second refused ("You already have an open complaint …") |
| K2 | open complaint, not resolved | advance the clock past day 10 | at-risk re-check escalates → Complaint escalation for Compliance & grievance (title names TurfAI's escalate-to) |
| K3 | resolution task | Add a case note | note on the case; the same task returns |
| K4 | Ombudsman / regulator matter | raise a complaint that names the Ombudsman / regulator | TurfAI drafts a notice → Compliance Regulator notice sign-off |
| V1 | any policy | Ask a question about premiums / clauses | answered with citations (or Servicing escalation if out of scope) |
| V2 | any policy | Change nominee with shares not totalling 100 % | the insurer's record system refuses to write it ("nominee shares total N%, not 100%"): TurfAI is expected to hold / decline it; Apply the change on the escalation is refused |
| V3 |
6.6 Autonomy ladder
| # | Setup | Steps | Expected result |
|---|---|---|---|
| L1 | fresh reset, Clock → Semi-auto → Save | New customer… sign-up with sample details and a sample KYC → Submit application (§3.6) | uw_assess → memo Decided by Autopilot (8 checks) → policy_issue → POL-LIFE-2026-9NNNNN in force with no console touch; Decided view badge; Policy 360 event source system:autopilot; Dashboards → Underwriting → Auto-approved share counts it |
| L2 | as L1 | R1 (Kavya) applies at Semi-auto | TurfAI rates her (+50 %, or refers) → not clean → the memo waits for the underwriter as at HITL; the Decision card says "Left to you by the autopilot (Semi-auto): …" with the failing checks (payload autopilot.eligible: false) |
| L3 | Semi-auto; open memo in the inbox | switch to HITL → Save | the open memo stays open (not re-evaluated); the next uw_assess result waits too. Reset demo → badge Autonomy: HITL |
| L4 | Autonomous, limit ₹20,00,000 | A2's claim (S6) |
7. Tips, gotchas and known bugs
7.1 Working with the demo
- TurfAI takes minutes. Each run takes 40–250 s; a claim runs three workflows (intake, then fraud ∥ settlement). The Inbox, Runs, Apply, Ask, Payments, Report a claim, Raise a complaint pages and the storyline panel refresh themselves every 3 s while work is in flight; Policy 360, Offers, My policy and Dashboards do not — reload them.
- Watch Console → Runs to see what is pending, running, invalid or failed.
- The clock only goes forward. Plan the order of beats; to replay, Reset demo. Do not drive the clock from the CLI while the console is in use (K13).
- Plain-text uploads only (
.txt) everywhere — Apply, requirements, claims, SIU findings. Choose what each file is; it matters (the kind code goes into the document id that TurfAI sees). - "Use a sample" buttons (KYC, ITR / Form 16, Medical exam report, Lab report) write a document from the applicant's own details, labelled "Demo sample text" in the UI; TurfAI reads it as ordinary evidence. Medical / lab samples are clean (BP 122/80, HbA1c 5.3 %).
- No files needed for claims and SIU findings. Use sample documents on Report a claim and on Submit findings attaches the current Act as persona's storyline documents (console: the claim's customer), and "Report a death" opens with the persona's claim-form details already filled; Download a file to edit it and upload your own (§1.9).
- Sign-off signs TurfAI's recommendation. Sign off TurfAI's recommendation on a claim does exactly what
TurfAI recommended — admit, repudiate, or ask for documents — for the amount shown as Written to the claim.
Read the decision before you click. To disagree, use Ask for documents or Return for re-assessment (both
need a note); a return starts a live
claim_settlerun. With System-check mismatches the approve needs the acknowledgement tick (§2.7). - Documents go to the same claim. For a claim "More documents needed", the nominee uses on its card — not . starts a live (asked at triage) or (asked at settlement) run; a registration after the intake re-run starts fraud ∥ settlement too.
Rehearse a duplicate claim without TurfAI
npm run replay:a2-duplicate -w @uip/worker plays A2's duplicate
situation on the dev DB from recorded contracts (0 TurfAI runs): 11-02 the clean claim CLM-2026-000311 → registered
→ settlement admit ∥ fraud clear → awaiting sign-off; 11-04 the same death reported again with the Report the same
death again set → CLM-2026-000311-2 in Claim triage. Options (environment variables):
UIP_REPLAY_DUP=insurer(default) — TurfAI links nothing, the insurer's records show 311 open (the C2a view: "TurfAI did not link it", Link as duplicate from the insurer's records);UIP_REPLAY_DUP=turfai— TurfAI's recorded duplicate contract,duplicate_ofCLM-2026-000311 (the C3 view).UIP_REPLAY_STOP=signoff— stop with 311 awaiting sign-off, before the second report (to show the portal notice and Report this death again).
The dev worker must not run while it replays — it would send the pending intake / fraud / settlement runs to TurfAI before the script completes them. The script checks this itself and refuses to start (exit 2, nothing written) when CLM-2026-000311 already exists (no fresh reset), when a TurfAI run is in flight, or when this repo's worker process is running and not paused ("the dev worker is running (pid …) — pause it first: kill -STOP …"). It quiets the TurfAI billing / renewal scopes while it replays and puts them back as they were at the end (other demo settings, e.g. the autonomy level, untouched):
npm run demo:reset(with the worker running or not).- Stop or pause the worker: either stop
npm run dev(Ctrl+C) and start only the web withnpm run dev -w @uip/web, or pause the worker process in place:kill -STOP $(pgrep -f '^\S*node .*loader\.mjs src/main\.ts')(the worker's node child oftsx watch;pgrepalone shows the pid). npm run replay:a2-duplicate -w @uip/worker(e.g.UIP_REPLAY_DUP=turfai npm run replay:a2-duplicate -w @uip/worker). It prints the second claim's triage task title and warns if any run is left pending (normally none).- Resume the worker:
kill -CONT $(pgrep -f '^\S*node .*loader\.mjs src/main\.ts'), or startnpm run devagain. Do not keep it paused across ademo:reset; iftsx watchrestarted the worker (a code change) pause the new process.
Then work the triage in the console. Link as duplicate needs no TurfAI; Register the claim, a portal
Submit claim after UIP_REPLAY_STOP=signoff, or signing off 311 start live TurfAI runs once the worker is back.
Rehearse the documents loop and the sign-off overrides
The same script (same guard and worker-pause steps 1–4 above) has two more modes for Phase 16:
npm run replay:a2-requirements -w @uip/worker— on 11-02 Karthik reports 311 with the Incomplete death claim set (claim form + death certificate only); the recorded intake is patched to TurfAIrequirements(KYC and bank proof outstanding) → a Claim triage task, and it stops there. Then: Ask for documents → portal Add documents (§6 C14). The re-run after Send documents is live (worker resumed).UIP_REPLAY_STOP=signoff npm run replay:a2-duplicate -w @uip/worker— 311 awaiting sign-off (admit ₹27,67,173), for Ask for documents (no TurfAI until the nominee sends documents), Return for re-assessment (one liveclaim_settlerun) and the TAT clock (C16, C18).UIP_REPLAY_STOP=signoff UIP_REPLAY_SETTLE=mismatch npm run replay:a2-duplicate -w @uip/worker— the same, with TurfAI's net payable +₹1,000 so the sign-off carries System-check mismatches: the acknowledgement checkbox and both figures beside Written to the claim (C17). Approving it needs no TurfAI.
Recorded settlement contracts are re-timed to the replay's dates, so the TAT System checks agree. To show a red /
paused clock, advance the clock with the worker still paused (tip above), then demo:reset.
7.2 Known open items a tester may hit (plan §13.1)
| # | What you will see |
|---|---|
| K1 | ~2 % of runs fail inside TurfAI ("expected json"); absorbed by the automatic re-trigger, else a System task |
| K10 | no console toggle for the billing / renewal scope (SQL only); the autonomy level has one (Clock page, §1.8) |
| K11 | a completed_with_errors run with a valid contract may still show as not finished on a few pages |
| K13 | the CLI clock bypasses the console's settle / lock — avoid mixing |
| K16 | (documents for a claim waiting for them: fixed in P16.2 — Add documents, §3.4) Compliance cannot return a notice draft; no breach-date complaint re-check; no console form for contact-centre complaints; premium-mode change recorded but never applied; free-look refund without finance approval; late first premium (pending_first_premium) unreachable from the portal; reset does not run the clock-start-day scan |
| K17 | the expired-mandate billing scenario cannot be shown live |
| K18 | TurfAI judgement variance |
| — | Rejected issuance (issuance_rejected) has no UI to re-run issuance |
| — | [Fixed in P16.2: a claim put on "Ask for documents" — at triage or at sign-off — now takes the nominee's documents on the same claim (Add documents) and TurfAI re-checks / re-assesses it; no second claim is needed.] |
7.3 Known bugs (verified in code)
- [Fixed in P16.1:
coverOnDatereturnsoutside_term(not in force) for a date of death before the RCD, checked before every other branch; settlement's in-grace check follows — §6 C1.] Insurer in-force check ignores the risk-commencement date.coverOnDateinapps/worker/src/mappers/claim-intake.ts:46-60treats a death after maturity asoutside_term, and checks lapse / paid-to / grace, but never checks a date of death before the RCD. For a new policy (paid-to date after the death) it returns in force (premium_paid). TurfAI's intake rules (INT-3: "outside_term when d is before risk commencement") say not in force, so the claim gets avalidation.policy_in_force/in_force_basismismatch and is held in triage instead of being registered for adjudication. The same function feeds settlement's in-grace deduction check (claim-settle.ts:72). - [Fixed in P15.2: Link as duplicate is now also offered from the insurer's own open claims on the policy, the
title names the possible duplicate first, and Register over another open claim needs a note; P15.3 adds the
Other claims box, the "TurfAI did not link it" warning, and keeps a re-report on a policy with a settled claim
out of auto-registration — §2.7.]
"Link as duplicate" only when TurfAI flags the duplicate. The triage options were
routing.duplicate_of ? [register, request_documents, link_duplicate] : [register, request_documents](claim-intake.ts:297) and the decision handler refuses without it. The insurer's own duplicate check (claim-intake.ts:130: any other open claim on the policy, regardless of date of death) only produces a mismatch — the officer then cannot link the duplicate, only register it or ask for documents. Conversely a second claim with a different date of death is flagged as a duplicate mismatch by the insurer although TurfAI's rule (INT-5: same policy, life and date of death) says it is not one.
8. Glossary
| Term | Meaning |
|---|---|
| APS | Attending physician's statement — the treating doctor's report, called for by the manual for some conditions (UWM-4) |
| Arrears | Unpaid regular premiums of a lapsed policy, paid with interest on revival |
| Autonomy level | Demo setting (Console → Clock): HITL · Semi-auto · Autonomous — which clean TurfAI gates the orchestrator may close itself (§1.8). Autonomous is demo only: the specs have a claims officer approve every claim; the autopilot never repudiates, never signs a substantiated fraud case and never pays above the limit |
| Autopilot | The orchestrator applying TurfAI's own recommendation to a clean gate task when the autonomy level permits it; decided_by / event source system:autopilot; never a judgement of its own |
| Contestability / s.45 | Insurance Act 1938 s.45: within 3 years of the later of RCD and last revival the insurer may repudiate for material non-disclosure or fraud; after that it cannot. "Early claim" = death inside this window |
| Contract | The validated JSON output of a TurfAI workflow (Contract-<id> node); the app uses nothing else |
| Counter-offer | Revised terms (loading, exclusions, lower sum assured or other term) the applicant must accept before issue |