# Synthetic Avouch example for Avouch Studio: insurance claims, from first notice to payout. # All names and quotes are invented. It shows an approval and investigation flow across four contexts: # approval limits as a decision table, a fraud review that holds the claim, and a claim that can be reopened. formatVersion: 1 contexts: PolicyAdmin: Policy administration - policies and their coverages Claims: Claims, assessments and adjusters Finance: Reserves and payouts SpecialInvestigations: Special investigations - fraud reviews infrastructureStores: [audit_log, document_store] permission_rows_not_commands: - name: Export loss ratio report reason: Actuarial report; it reads closed claims and changes nothing cite: { doc: 'claims#permissions', quote: The loss ratio export needs report:actuarial } knownSourceGaps: - id: G1 rule: R6 kind: effect_unspecified keys: ['FILE_CLAIM:reserve_claim'] doc_line: 'claims#first-notice; finance#reserves' conflict: The claims handbook says an initial reserve is set when the claim is filed; the finance manual says the first reserve follows the first assessment proposed: Agree on one rule and state it in both claims#first-notice and finance#reserves - id: G2 rule: R10 kind: permission_unknown keys: [CONFIRM_FRAUD] doc_line: 'siu#decisions; claims#permissions' conflict: The SIU manual says only the SIU lead confirms fraud; the claims permission table gives the same right to claims managers proposed: Name one permission key for confirming fraud in claims#permissions and cite it in siu#decisions - id: G3 rule: R6 kind: effect_unspecified keys: ['REOPEN_CLAIM:claim_adjuster'] doc_line: 'claims#reopen' conflict: The reopen section does not say whether a reopened claim keeps its adjuster proposed: State in claims#reopen whether the adjuster is kept or the claim goes back to the assignment queue outOfScopeObjectTypes: Policyholder: Policyholder records live in the customer system; claims refer to them by number only Bank: Payout transfers run through the bank; this file sees only the result scope: by: insurer_id global: - { type: Adjuster, cite: { doc: 'claims#adjusters', quote: Independent adjusters work for every insurer on the platform } } cite: { doc: 'claims#tenancy', quote: 'Every policy, claim, reserve and payout belongs to one insurer by insurer_id' } dispositions: REJECTED: { class: rejected, cite: { doc: 'claims#results', quote: REJECTED means the request changed nothing } } APPLIED: { class: applied, cite: { doc: 'claims#results', quote: APPLIED means the change is stored } } APPROVED: { class: applied, cite: { doc: 'claims#results', quote: APPROVED means the claim is accepted and a payout is requested } } REFERRED: { class: pending, cite: { doc: 'claims#results', quote: REFERRED means a person with a higher approval limit must decide } } PAYOUT_SENT: { class: pending, cite: { doc: 'claims#results', quote: PAYOUT_SENT means the bank has the transfer and its result is still to come } } objectTypes: Policy: context: PolicyAdmin datasource: policies doc: 'policy#policies' properties: status: class: canonical type: enum cite: { doc: 'policy#policies', quote: 'A policy is IN_FORCE, LAPSED or CANCELLED' } Coverage: context: PolicyAdmin datasource: coverages doc: 'policy#coverages' properties: peril: class: canonical type: enum cite: { doc: 'policy#coverages', quote: 'Each coverage insures one peril such as FIRE, WATER or THEFT' } starts_on: class: canonical type: date cite: { doc: 'policy#coverages', quote: Cover begins on the start date } ends_on: class: canonical type: date cite: { doc: 'policy#coverages', quote: Cover ends at the end of the end date } limit: class: canonical type: integer cite: { doc: 'policy#coverages', quote: The limit is the most the coverage pays for one claim } Claim: context: Claims datasource: claims doc: 'claims#claims' properties: status: class: canonical type: enum cite: { doc: 'claims#claims', quote: 'Claim status changes only through claim, investigation and payout actions' } incident_on: class: canonical type: date cite: { doc: 'claims#first-notice', quote: The claimant gives the date of the incident } assessed_amount: class: canonical type: integer cite: { doc: 'claims#assessment', quote: 'The assessed amount is the loss the adjuster accepts, in minor units' } closed_at: class: canonical type: timestamp cite: { doc: 'claims#reopen', quote: The time a claim is closed is kept for the reopen window } reopen_window: class: policy type: duration cite: { doc: 'claims#reopen', quote: Each insurer sets how long a closed claim may be reopened } Adjuster: context: Claims datasource: adjusters doc: 'claims#adjusters' properties: status: class: canonical type: enum cite: { doc: 'claims#adjusters', quote: An adjuster is ON_DUTY or OFF_DUTY } open_claims: class: canonical type: integer cite: { doc: 'claims#adjusters', quote: The open claim count rises with each assignment } Assessment: context: Claims datasource: assessments doc: 'claims#assessment' properties: amount: class: canonical type: integer cite: { doc: 'claims#assessment', quote: Each assessment states the loss found on that visit or review } method: class: canonical type: enum cite: { doc: 'claims#assessment', quote: An assessment is a DESK review or a FIELD visit } Reserve: context: Finance datasource: reserves doc: 'finance#reserves' properties: amount: class: canonical type: integer cite: { doc: 'finance#reserves', quote: A reserve is money set aside for the expected cost of one claim } Payout: context: Finance datasource: payouts doc: 'finance#payouts' properties: status: class: canonical type: enum cite: { doc: 'finance#payouts', quote: Payout status follows the bank transfer } amount: class: canonical type: integer cite: { doc: 'finance#payouts', quote: The payout amount is the approved amount less the deductible } FraudReview: context: SpecialInvestigations datasource: fraud_reviews doc: 'siu#reviews' properties: status: class: canonical type: enum cite: { doc: 'siu#reviews', quote: A fraud review is OPEN until the SIU clears or confirms it } reason: class: canonical type: enum cite: { doc: 'siu#reviews', quote: 'The referral reason is RED_FLAG, PATTERN or TIP' } stateMachines: Claim: doc: 'claims#claim-states' initial: FILED terminal: [WITHDRAWN] transitions: - { from: FILED, to: UNDER_ASSESSMENT, by: [ASSIGN_ADJUSTER] } - { from: FILED, to: WITHDRAWN, by: [WITHDRAW_CLAIM] } - { from: UNDER_ASSESSMENT, to: ON_HOLD, by: [REFER_TO_SIU] } - { from: ON_HOLD, to: UNDER_ASSESSMENT, by: [CLEAR_FRAUD_REVIEW] } - { from: ON_HOLD, to: DENIED, by: [CONFIRM_FRAUD] } - { from: UNDER_ASSESSMENT, to: APPROVED, by: [APPROVE_CLAIM] } - { from: UNDER_ASSESSMENT, to: DENIED, by: [DENY_CLAIM] } - { from: APPROVED, to: CLOSED, by: [RECORD_PAYOUT_RESULT] } - { from: CLOSED, to: REOPENED, by: [REOPEN_CLAIM] } - { from: REOPENED, to: UNDER_ASSESSMENT, by: [ASSIGN_ADJUSTER] } - { from: DENIED, to: REOPENED, by: [], out_of_scope: An appeal against a denial goes to the external ombudsman; staff reopen the claim by hand if it succeeds } Payout: doc: 'finance#payout-states' initial: REQUESTED terminal: [SETTLED, CANCELLED] transitions: - { from: REQUESTED, to: ISSUED, by: [ISSUE_PAYOUT] } - { from: REQUESTED, to: CANCELLED, by: [CANCEL_PAYOUT] } - { from: ISSUED, to: SETTLED, by: [RECORD_PAYOUT_RESULT] } - { from: ISSUED, to: RETURNED, by: [RECORD_PAYOUT_RESULT] } - { from: RETURNED, to: ISSUED, by: [ISSUE_PAYOUT] } - { from: RETURNED, to: CANCELLED, by: [CANCEL_PAYOUT] } FraudReview: doc: 'siu#review-states' initial: OPEN terminal: [CLEARED, CONFIRMED, REFERRED_TO_POLICE] transitions: - { from: OPEN, to: CLEARED, by: [CLEAR_FRAUD_REVIEW] } - { from: OPEN, to: CONFIRMED, by: [CONFIRM_FRAUD] } - { from: OPEN, to: REFERRED_TO_POLICE, by: [], out_of_scope: The SIU lead files police referrals outside this system } linkTypes: - { id: coverage_policy, from: Coverage, to: Policy, cardinality: 'N:1', via: policy_id, doc: 'policy#coverages' } - { id: claim_coverage, from: Claim, to: Coverage, cardinality: 'N:1', via: coverage_id, doc: 'claims#first-notice' } - { id: claim_adjuster, from: Claim, to: Adjuster, cardinality: 'N:1', via: adjuster_id, doc: 'claims#assignment' } - { id: assessment_claim, from: Assessment, to: Claim, cardinality: 'N:1', via: claim_id, doc: 'claims#assessment' } - { id: assessment_adjuster, from: Assessment, to: Adjuster, cardinality: 'N:1', via: adjuster_id, doc: 'claims#assessment' } - { id: reserve_claim, from: Reserve, to: Claim, cardinality: 'N:1', via: claim_id, doc: 'finance#reserves' } - { id: payout_claim, from: Payout, to: Claim, cardinality: 'N:1', via: claim_id, doc: 'finance#payouts' } - { id: fraud_review_claim, from: FraudReview, to: Claim, cardinality: 'N:1', via: claim_id, doc: 'siu#reviews' } derivedProperties: within_reopen_window: of: Claim doc: 'claims#reopen' doc_term: Within the reopen window type: boolean expr: { lte: [{ ref: now }, { plus: [{ ref: self.closed_at }, { ref: self.reopen_window }] }] } cite: { doc: 'claims#reopen', quote: A closed claim can be reopened until its reopen window has passed since it was closed } outstanding_reserve: of: Claim doc: 'finance#reserves' doc_term: Outstanding reserve is the sum of the reserves less the settled payouts reads: [Reserve.amount, Payout.amount, Payout.status] actionTypes: FILE_CLAIM: context: Claims doc: 'claims#first-notice' doc_term: File a claim permission: any_of: - keys: ['claims:file'] cite: { doc: 'claims#permissions', quote: Call centre staff file claims with claims:file } - keys: ['portal:claims'] cite: { doc: 'claims#permissions', quote: Policyholders file online with portal:claims } principals: { kinds: [policyholder], cite: { doc: 'claims#permissions', quote: The portal key belongs to policyholders only } } parameters: coverage_id: { type: { ref: Coverage }, cite: { doc: 'claims#first-notice', quote: The claimant picks the coverage_id that applies } } incident_on: { type: date, cite: { doc: 'claims#first-notice', quote: The claimant enters incident_on } } peril: { type: enum, cite: { doc: 'claims#first-notice', quote: The claimant names the peril that caused the loss } } conditions: - id: policy_in_force expr: exists: as: p in: { nav: { from: { ref: coverage_id }, link: coverage_policy, dir: forward } } where: { and: [{ isNotNull: [{ ref: p.status }] }, { eq: [{ ref: p.status }, { lit: IN_FORCE }] }] } cites: [{ cite: { doc: 'claims#first-notice', quote: A claim is accepted only on an IN_FORCE policy } }] scenarios: [CLM-01.S1] - id: incident_in_cover expr: and: - { gte: [{ ref: incident_on }, { ref: coverage_id.starts_on }] } - { lte: [{ ref: incident_on }, { ref: coverage_id.ends_on }] } cites: [{ cite: { doc: 'claims#first-notice', quote: The incident must fall between the start and end dates of the coverage } }] scenarios: [CLM-01.S2] - id: peril_covered expr: { eq: [{ ref: peril }, { ref: coverage_id.peril }] } cites: [{ cite: { doc: 'claims#first-notice', quote: The peril of the claim must be the peril of the coverage } }] decision: hitPolicy: first rows: - when: { fails: policy_in_force } result: REJECTED cites: [{ cite: { doc: 'claims#first-notice', quote: A claim on a lapsed or cancelled policy is REJECTED } }] - when: { fails: incident_in_cover } result: REJECTED cites: [{ cite: { doc: 'claims#first-notice', quote: An incident outside the cover dates is REJECTED } }] - when: { fails: peril_covered } result: REJECTED cites: [{ cite: { doc: 'claims#first-notice', quote: A loss from a peril the coverage does not insure is REJECTED } }] otherwise: { result: APPLIED, cites: [{ cite: { doc: 'claims#first-notice', quote: Otherwise the claim is created as FILED and the notice is APPLIED } }] } creates: [Claim] edits: [] link_effects: claim_coverage: effect: The new claim points to the chosen coverage cite: { doc: 'claims#first-notice', quote: Every claim is made under one coverage } scenarios: [CLM-01.S1] claim_adjuster: { none: An adjuster is assigned in a later step } assessment_claim: { none: A new claim has no assessment yet } reserve_claim: unspecified: The claims handbook and the finance manual disagree on whether filing sets a first reserve cite: { doc: 'claims#first-notice', quote: An initial reserve is set when the claim is filed } payout_claim: { none: A new claim has no payout } fraud_review_claim: { none: A new claim has no fraud review } emits: [ClaimFiled] evidence: fileClaim WITHDRAW_CLAIM: context: Claims doc: 'claims#withdraw' doc_term: Withdraw claim permission: none: The policyholder withdraws in the portal; no staff key is needed cite: { doc: 'claims#permissions', quote: Withdrawing a filed claim needs no permission key } parameters: claim_id: { type: { ref: Claim }, cite: { doc: 'claims#withdraw', quote: The policyholder withdraws claim_id } } conditions: - id: claim_filed expr: { eq: [{ ref: claim_id.status }, { lit: FILED }] } cites: [{ cite: { doc: 'claims#withdraw', quote: Only a FILED claim can be withdrawn; after assignment the adjuster must close it } }] decision: hitPolicy: first rows: - when: { fails: claim_filed } result: REJECTED cites: [{ cite: { doc: 'claims#withdraw', quote: Withdrawing a claim already in assessment is REJECTED } }] otherwise: { result: APPLIED, cites: [{ cite: { doc: 'claims#withdraw', quote: Otherwise the claim becomes WITHDRAWN and the withdrawal is APPLIED } }] } edits: [Claim.status] link_effects: claim_coverage: { none: Withdrawing keeps the coverage } claim_adjuster: { none: A filed claim has no adjuster } assessment_claim: { none: A filed claim has no assessment } reserve_claim: { none: Finance releases reserves in its own run } payout_claim: { none: A filed claim has no payout } fraud_review_claim: { none: A filed claim has no fraud review } emits: [ClaimWithdrawn] ASSIGN_ADJUSTER: context: Claims doc: 'claims#assignment' doc_term: Assign adjuster permission: keys: ['claims:assign'] cite: { doc: 'claims#permissions', quote: Team leads assign adjusters with claims:assign } parameters: claim_id: { type: { ref: Claim }, cite: { doc: 'claims#assignment', quote: The team lead picks the claim_id from the queue } } adjuster_id: { type: { ref: Adjuster }, cite: { doc: 'claims#assignment', quote: The team lead picks an adjuster_id with capacity } } conditions: - id: claim_waiting expr: { in: [{ ref: claim_id.status }, { lit: [FILED, REOPENED] }] } cites: [{ cite: { doc: 'claims#assignment', quote: FILED and REOPENED claims wait in the assignment queue } }] - id: adjuster_on_duty expr: { eq: [{ ref: adjuster_id.status }, { lit: ON_DUTY }] } cites: [{ cite: { doc: 'claims#assignment', quote: Only an adjuster who is ON_DUTY takes new claims } }] - id: adjuster_has_capacity expr: { lt: [{ ref: adjuster_id.open_claims }, { lit: 30 }] } cites: [{ cite: { doc: 'claims#assignment', quote: An adjuster holds fewer than 30 open claims } }] decision: hitPolicy: first rows: - when: { fails: claim_waiting } result: REJECTED cites: [{ cite: { doc: 'claims#assignment', quote: Assigning a claim that is not waiting is REJECTED } }] - when: { fails: adjuster_on_duty } result: REJECTED cites: [{ cite: { doc: 'claims#assignment', quote: Assigning to an adjuster who is off duty is REJECTED } }] - when: { fails: adjuster_has_capacity } result: REJECTED cites: [{ cite: { doc: 'claims#assignment', quote: Assigning to a full adjuster is REJECTED } }] otherwise: { result: APPLIED, cites: [{ cite: { doc: 'claims#assignment', quote: Otherwise the claim moves to UNDER_ASSESSMENT and the assignment is APPLIED } }] } edits: [Claim.status, Adjuster.open_claims] link_effects: claim_adjuster: effect: The claim points to the assigned adjuster cite: { doc: 'claims#assignment', quote: A claim has one adjuster at a time } claim_coverage: { none: Assignment keeps the coverage } assessment_claim: { none: Assignment does not assess } assessment_adjuster: { none: Earlier assessments keep their adjuster } reserve_claim: { none: Assignment does not reserve } payout_claim: { none: Assignment does not pay } fraud_review_claim: { none: Assignment does not refer } emits: [AdjusterAssigned] RECORD_ASSESSMENT: context: Claims doc: 'claims#assessment' doc_term: Record assessment permission: keys: ['claims:assess'] cite: { doc: 'claims#permissions', quote: Adjusters record assessments with claims:assess } principals: { kinds: [staff], cite: { doc: 'claims#permissions', quote: 'Assessments are entered by staff, never by the policyholder' } } parameters: claim_id: { type: { ref: Claim }, cite: { doc: 'claims#assessment', quote: The adjuster assesses claim_id } } amount: { type: integer, cite: { doc: 'claims#assessment', quote: The adjuster enters the amount of the loss } } method: { type: enum, cite: { doc: 'claims#assessment', quote: The adjuster states the method used } } conditions: - id: claim_under_assessment expr: { eq: [{ ref: claim_id.status }, { lit: UNDER_ASSESSMENT }] } cites: [{ cite: { doc: 'claims#assessment', quote: Assessments are taken while the claim is UNDER_ASSESSMENT } }] - id: within_coverage_limit expr: exists: as: c in: { nav: { from: { ref: claim_id }, link: claim_coverage, dir: forward } } where: { and: [{ isNotNull: [{ ref: c.limit }] }, { lte: [{ ref: amount }, { ref: c.limit }] }] } cites: [{ cite: { doc: 'claims#assessment', quote: 'An assessed loss above the coverage limit is capped by a supervisor, not entered' } }] decision: hitPolicy: first rows: - when: { fails: claim_under_assessment } result: REJECTED cites: [{ cite: { doc: 'claims#assessment', quote: An assessment outside the assessment stage is REJECTED } }] - when: { fails: within_coverage_limit } result: REJECTED cites: [{ cite: { doc: 'claims#assessment', quote: An assessment above the limit is REJECTED } }] otherwise: { result: APPLIED, cites: [{ cite: { doc: 'claims#assessment', quote: 'Otherwise the assessment is stored, the claim takes its amount, and the entry is APPLIED' } }] } creates: [Assessment] edits: [Claim.assessed_amount] edit_cites: Claim.assessed_amount: { cite: { doc: 'claims#assessment', quote: The latest assessment sets the assessed amount of the claim } } link_effects: assessment_claim: effect: The new assessment points to the claim cite: { doc: 'claims#assessment', quote: An assessment belongs to one claim } assessment_adjuster: effect: The new assessment points to the adjuster who made it cite: { doc: 'claims#assessment', quote: The assessment is signed by the adjuster who made it } claim_coverage: { none: Assessing keeps the coverage } claim_adjuster: { none: Assessing keeps the adjuster } reserve_claim: { none: Finance adjusts reserves in its own action } payout_claim: { none: Assessing does not pay } fraud_review_claim: { none: Assessing does not refer } emits: [AssessmentRecorded] SET_RESERVE: context: Finance doc: 'finance#reserves' doc_term: Set reserve permission: keys: ['reserve:set'] cite: { doc: 'claims#permissions', quote: Reserves are set with reserve:set } parameters: claim_id: { type: { ref: Claim }, cite: { doc: 'finance#reserves', quote: A reserve is set for claim_id } } amount: { type: integer, cite: { doc: 'finance#reserves', quote: The reserve amount is the expected cost } } conditions: - id: claim_open expr: { in: [{ ref: claim_id.status }, { lit: [UNDER_ASSESSMENT, ON_HOLD, APPROVED, REOPENED] }] } cites: [{ cite: { doc: 'finance#reserves', quote: 'Reserves are kept on UNDER_ASSESSMENT, ON_HOLD, APPROVED and REOPENED claims' } }] - id: amount_not_negative expr: { gte: [{ ref: amount }, { lit: 0 }] } cites: [{ cite: { doc: 'finance#reserves', quote: A reserve is 0 or more; 0 releases it } }] decision: hitPolicy: first rows: - when: { fails: claim_open } result: REJECTED cites: [{ cite: { doc: 'finance#reserves', quote: A reserve on a closed or withdrawn claim is REJECTED } }] - when: { fails: amount_not_negative } result: REJECTED cites: [{ cite: { doc: 'finance#reserves', quote: A negative reserve is REJECTED } }] otherwise: { result: APPLIED, cites: [{ cite: { doc: 'finance#reserves', quote: Otherwise a new reserve line is written and the reserve is APPLIED } }] } creates: [Reserve] edits: [] link_effects: reserve_claim: effect: The new reserve line points to the claim cite: { doc: 'finance#reserves', quote: Each reserve line belongs to one claim } emits: [ReserveSet] REFER_TO_SIU: context: Claims doc: 'siu#referral' doc_term: Refer to special investigations permission: keys: ['claims:refer-siu'] cite: { doc: 'claims#permissions', quote: Adjusters refer a claim to the SIU with claims:refer-siu } parameters: claim_id: { type: { ref: Claim }, cite: { doc: 'siu#referral', quote: The adjuster refers claim_id } } reason: { type: enum, cite: { doc: 'siu#referral', quote: The adjuster gives the reason for the referral } } conditions: - id: claim_under_assessment expr: { eq: [{ ref: claim_id.status }, { lit: UNDER_ASSESSMENT }] } cites: [{ cite: { doc: 'siu#referral', quote: A claim is referred while it is UNDER_ASSESSMENT } }] - id: no_open_review expr: none: as: r in: { nav: { from: { ref: claim_id }, link: fraud_review_claim, dir: reverse } } where: { and: [{ isNotNull: [{ ref: r.status }] }, { eq: [{ ref: r.status }, { lit: OPEN }] }] } cites: [{ cite: { doc: 'siu#referral', quote: A claim has at most one OPEN fraud review } }] scenarios: [CLM-04.S1] decision: hitPolicy: first rows: - when: { fails: claim_under_assessment } result: REJECTED cites: [{ cite: { doc: 'siu#referral', quote: Referring a claim outside assessment is REJECTED } }] - when: { fails: no_open_review } result: REJECTED cites: [{ cite: { doc: 'siu#referral', quote: A second referral while one is open is REJECTED } }] otherwise: { result: APPLIED, cites: [{ cite: { doc: 'siu#referral', quote: 'Otherwise the review is opened, the claim goes ON_HOLD and the referral is APPLIED' } }] } creates: [FraudReview] edits: [Claim.status] crossContext: via: same_batch cite: { doc: 'siu#referral', quote: The fraud review is opened in the same batch that puts the claim on hold } link_effects: fraud_review_claim: effect: The new fraud review points to the referred claim cite: { doc: 'siu#reviews', quote: Each fraud review looks at one claim } scenarios: [CLM-04.S1] claim_coverage: { none: Referral keeps the coverage } claim_adjuster: { none: The adjuster stays on the claim during the review } assessment_claim: { none: Referral does not assess } reserve_claim: { none: Referral does not reserve } payout_claim: { none: Referral does not pay } emits: [ClaimReferred] CLEAR_FRAUD_REVIEW: context: SpecialInvestigations doc: 'siu#decisions' doc_term: Clear fraud review permission: keys: ['siu:decide'] cite: { doc: 'siu#decisions', quote: An investigator clears a review with siu:decide } parameters: review_id: { type: { ref: FraudReview }, cite: { doc: 'siu#decisions', quote: The investigator closes review_id } } conditions: - id: review_open expr: { eq: [{ ref: review_id.status }, { lit: OPEN }] } cites: [{ cite: { doc: 'siu#decisions', quote: Only an OPEN review can be cleared } }] - id: claim_on_hold expr: exists: as: c in: { nav: { from: { ref: review_id }, link: fraud_review_claim, dir: forward } } where: { and: [{ isNotNull: [{ ref: c.status }] }, { eq: [{ ref: c.status }, { lit: ON_HOLD }] }] } cites: [{ cite: { doc: 'siu#decisions', quote: The claim under review stays ON_HOLD until the decision } }] decision: hitPolicy: first rows: - when: { fails: review_open } result: REJECTED cites: [{ cite: { doc: 'siu#decisions', quote: Clearing a closed review is REJECTED } }] - when: { fails: claim_on_hold } result: REJECTED cites: [{ cite: { doc: 'siu#decisions', quote: Clearing a review whose claim is not on hold is REJECTED } }] otherwise: { result: APPLIED, cites: [{ cite: { doc: 'siu#decisions', quote: 'Otherwise the review is CLEARED, the claim returns to assessment, and the decision is APPLIED' } }] } edits: [FraudReview.status, Claim.status] crossContext: via: same_batch cite: { doc: 'siu#decisions', quote: The SIU decision and the claim release are written together } link_effects: fraud_review_claim: { none: The review keeps its claim } claim_coverage: { none: Clearing keeps the coverage } claim_adjuster: { none: The same adjuster resumes the claim } assessment_claim: { none: Clearing does not assess } reserve_claim: { none: Clearing does not reserve } payout_claim: { none: Clearing does not pay } emits: [FraudReviewCleared] CONFIRM_FRAUD: context: SpecialInvestigations doc: 'siu#decisions' doc_term: Confirm fraud permission: unknown parameters: review_id: { type: { ref: FraudReview }, cite: { doc: 'siu#decisions', quote: The SIU confirms fraud on review_id } } conditions: - id: review_open expr: { eq: [{ ref: review_id.status }, { lit: OPEN }] } cites: [{ cite: { doc: 'siu#decisions', quote: Fraud is confirmed only on an OPEN review } }] decision: hitPolicy: first rows: - when: { fails: review_open } result: REJECTED cites: [{ cite: { doc: 'siu#decisions', quote: Confirming fraud on a closed review is REJECTED } }] otherwise: { result: APPLIED, cites: [{ cite: { doc: 'siu#decisions', quote: 'Otherwise the review is CONFIRMED, the claim is DENIED, and the decision is APPLIED' } }] } edits: [FraudReview.status, Claim.status] crossContext: via: same_batch cite: { doc: 'siu#decisions', quote: A confirmed fraud denies the claim in the same batch } link_effects: fraud_review_claim: { none: The review keeps its claim } claim_coverage: { none: Denial keeps the coverage } claim_adjuster: { none: Denial keeps the adjuster on record } assessment_claim: { none: Denial does not assess } reserve_claim: { none: Finance releases the reserve in its own run } payout_claim: { none: A denied claim gets no payout } emits: [FraudConfirmed] APPROVE_CLAIM: context: Claims doc: 'claims#approval' doc_term: Approve claim permission: any_of: - keys: ['claims:approve:adjuster'] cite: { doc: 'claims#permissions', quote: Adjusters approve small claims with claims:approve:adjuster } - keys: ['claims:approve:manager'] cite: { doc: 'claims#permissions', quote: Claims managers approve with claims:approve:manager } - keys: ['claims:approve:director'] cite: { doc: 'claims#permissions', quote: The claims director approves with claims:approve:director } parameters: claim_id: { type: { ref: Claim }, cite: { doc: 'claims#approval', quote: The approver opens claim_id } } conditions: - id: claim_assessed expr: and: - { eq: [{ ref: claim_id.status }, { lit: UNDER_ASSESSMENT }] } - { isNotNull: [{ ref: claim_id.assessed_amount }] } cites: [{ cite: { doc: 'claims#approval', quote: A claim is approved from UNDER_ASSESSMENT and only after it has an assessed amount } }] scenarios: [CLM-06.S1] - id: no_open_review expr: none: as: r in: { nav: { from: { ref: claim_id }, link: fraud_review_claim, dir: reverse } } where: { and: [{ isNotNull: [{ ref: r.status }] }, { eq: [{ ref: r.status }, { lit: OPEN }] }] } cites: [{ cite: { doc: 'claims#approval', quote: No claim is approved while a fraud review is OPEN } }] - id: adjuster_limit expr: and: - { isNotNull: [{ ref: claim_id.assessed_amount }] } - { lte: [{ ref: claim_id.assessed_amount }, { lit: 10000 }] } - { in: [{ lit: 'claims:approve:adjuster' }, { ref: actor.keys }] } cites: [{ cite: { doc: 'claims#approval', quote: 'With claims:approve:adjuster an adjuster approves up to 10000' } }] scenarios: [CLM-06.S2] - id: manager_limit expr: and: - { isNotNull: [{ ref: claim_id.assessed_amount }] } - { lte: [{ ref: claim_id.assessed_amount }, { lit: 100000 }] } - { in: [{ lit: 'claims:approve:manager' }, { ref: actor.keys }] } cites: [{ cite: { doc: 'claims#approval', quote: 'With claims:approve:manager a claims manager approves up to 100000' } }] scenarios: [CLM-06.S3] - id: director_signs expr: { in: [{ lit: 'claims:approve:director' }, { ref: actor.keys }] } cites: [{ cite: { doc: 'claims#approval', quote: 'Above 100000 only a holder of claims:approve:director signs' } }] decision: hitPolicy: first order: { cite: { doc: 'claims#approval', quote: The approval table is read from the top; the first matching row decides } } rows: - when: { fails: claim_assessed } result: REJECTED cites: [{ cite: { doc: 'claims#approval', quote: Approving a claim that is not assessed is REJECTED } }] - when: { fails: no_open_review } result: REJECTED cites: [{ cite: { doc: 'claims#approval', quote: Approving during a fraud review is REJECTED } }] - when: { passes: adjuster_limit } result: APPROVED cites: [{ cite: { doc: 'claims#approval', quote: Within the adjuster limit the claim is APPROVED by the adjuster } }] - when: { passes: manager_limit } result: APPROVED cites: [{ cite: { doc: 'claims#approval', quote: Within the manager limit the claim is APPROVED by the manager } }] - when: { passes: director_signs } result: APPROVED cites: [{ cite: { doc: 'claims#approval', quote: A director signature means the claim is APPROVED at any amount } }] otherwise: result: REFERRED cites: [{ cite: { doc: 'claims#approval', quote: Above the limit of the approver the claim is REFERRED upward } }] next: { actions: [APPROVE_CLAIM] } creates: [Payout] edits: [Claim.status] crossContext: via: same_batch cite: { doc: 'claims#approval', quote: Approval writes the payout request in the same batch } link_effects: payout_claim: effect: The new payout request points to the approved claim cite: { doc: 'finance#payouts', quote: Each payout pays one claim } scenarios: [CLM-06.S2] claim_coverage: { none: Approval keeps the coverage } claim_adjuster: { none: Approval keeps the adjuster } assessment_claim: { none: Approval does not add assessments } reserve_claim: { none: Finance moves the reserve when the payout settles } fraud_review_claim: { none: Approval does not refer } emits: [ClaimApproved] DENY_CLAIM: context: Claims doc: 'claims#denial' doc_term: Deny claim permission: keys: ['claims:deny'] cite: { doc: 'claims#permissions', quote: Denying a claim needs claims:deny } parameters: claim_id: { type: { ref: Claim }, cite: { doc: 'claims#denial', quote: The adjuster denies claim_id with a letter } } conditions: - id: claim_under_assessment expr: { eq: [{ ref: claim_id.status }, { lit: UNDER_ASSESSMENT }] } cites: [{ cite: { doc: 'claims#denial', quote: A claim is denied from UNDER_ASSESSMENT } }] decision: hitPolicy: first rows: - when: { fails: claim_under_assessment } result: REJECTED cites: [{ cite: { doc: 'claims#denial', quote: Denying a claim outside assessment is REJECTED } }] otherwise: { result: APPLIED, cites: [{ cite: { doc: 'claims#denial', quote: Otherwise the claim is DENIED and the letter is sent; the denial is APPLIED } }] } edits: [Claim.status] link_effects: claim_coverage: { none: Denial keeps the coverage } claim_adjuster: { none: Denial keeps the adjuster } assessment_claim: { none: Denial does not assess } reserve_claim: { none: Finance releases the reserve in its own run } payout_claim: { none: A denied claim gets no payout } fraud_review_claim: { none: Denial does not refer } emits: [ClaimDenied] ISSUE_PAYOUT: context: Finance doc: 'finance#payouts' doc_term: Issue payout permission: keys: ['payout:issue'] cite: { doc: 'claims#permissions', quote: Finance clerks send payouts with payout:issue } principals: { kinds: [staff], cite: { doc: 'claims#permissions', quote: Only finance staff send payouts } } idempotencyKey: required: true cite: { doc: 'finance#payouts', quote: Every payout request carries an idempotency key; the bank must never pay a claim twice } parameters: payout_id: { type: { ref: Payout }, cite: { doc: 'finance#payouts', quote: The clerk sends payout_id to the bank } } conditions: - id: payout_sendable expr: { in: [{ ref: payout_id.status }, { lit: [REQUESTED, RETURNED] }] } cites: [{ cite: { doc: 'finance#payouts', quote: A REQUESTED payout is sent; a RETURNED one is sent again with new bank details } }] - id: claim_approved expr: exists: as: c in: { nav: { from: { ref: payout_id }, link: payout_claim, dir: forward } } where: { and: [{ isNotNull: [{ ref: c.status }] }, { eq: [{ ref: c.status }, { lit: APPROVED }] }] } cites: [{ cite: { doc: 'finance#payouts', quote: Money leaves only for an APPROVED claim } }] scenarios: [CLM-07.S1] decision: hitPolicy: first rows: - when: { fails: payout_sendable } result: REJECTED cites: [{ cite: { doc: 'finance#payouts', quote: 'Sending a payout that is in transit, settled or cancelled is REJECTED' } }] - when: { fails: claim_approved } result: REJECTED cites: [{ cite: { doc: 'finance#payouts', quote: A payout for a claim that is no longer approved is REJECTED } }] otherwise: result: PAYOUT_SENT cites: [{ cite: { doc: 'finance#payouts', quote: Otherwise the transfer goes to the bank and the payout is PAYOUT_SENT } }] next: { actions: [RECORD_PAYOUT_RESULT] } edits: [Payout.status] link_effects: payout_claim: { none: Sending keeps the claim } emits: [PayoutIssued] evidence: issuePayout RECORD_PAYOUT_RESULT: context: Finance doc: 'finance#bank-results' doc_term: Record payout result permission: none: The bank reports back through a signed file; no user key is involved cite: { doc: 'claims#permissions', quote: Bank result files are checked by signature and need no permission key } parameters: payout_id: { type: { ref: Payout }, cite: { doc: 'finance#bank-results', quote: Each line of the bank file names a payout_id } } outcome: { type: enum, cite: { doc: 'finance#bank-results', quote: The bank reports SETTLED or RETURNED } } conditions: - id: payout_issued expr: { eq: [{ ref: payout_id.status }, { lit: ISSUED }] } cites: [{ cite: { doc: 'finance#bank-results', quote: A result applies only to an ISSUED payout } }] decision: hitPolicy: first rows: - when: { fails: payout_issued } result: REJECTED cites: [{ cite: { doc: 'finance#bank-results', quote: A result line for a payout not in transit is REJECTED } }] otherwise: { result: APPLIED, cites: [{ cite: { doc: 'finance#bank-results', quote: 'Otherwise the payout takes the bank result, a settled payout closes the claim, and the result is APPLIED' } }] } edits: [Payout.status, Claim.status, Claim.closed_at] edit_cites: Claim.status: { cite: { doc: 'finance#bank-results', quote: When the payout settles the claim moves from APPROVED to CLOSED } } crossContext: via: same_batch cite: { doc: 'finance#bank-results', quote: The payout result and the claim closure are one batch } link_effects: payout_claim: { none: The result keeps the claim } claim_coverage: { none: Closing keeps the coverage } claim_adjuster: { none: Closing keeps the adjuster on record } assessment_claim: { none: Closing does not assess } reserve_claim: { none: Finance releases the reserve in its own run } fraud_review_claim: { none: Closing does not refer } emits: [PayoutSettled, PayoutReturned] CANCEL_PAYOUT: context: Finance doc: 'finance#payouts' doc_term: Cancel payout permission: keys: ['payout:cancel'] cite: { doc: 'claims#permissions', quote: Cancelling a payout needs payout:cancel } parameters: payout_id: { type: { ref: Payout }, cite: { doc: 'finance#payouts', quote: A supervisor cancels payout_id } } conditions: - id: payout_not_in_transit expr: { in: [{ ref: payout_id.status }, { lit: [REQUESTED, RETURNED] }] } cites: [{ cite: { doc: 'finance#payouts', quote: Only a REQUESTED or RETURNED payout can be cancelled } }] decision: hitPolicy: first rows: - when: { fails: payout_not_in_transit } result: REJECTED cites: [{ cite: { doc: 'finance#payouts', quote: Cancelling a payout already at the bank is REJECTED } }] otherwise: { result: APPLIED, cites: [{ cite: { doc: 'finance#payouts', quote: Otherwise the payout becomes CANCELLED and the change is APPLIED } }] } edits: [Payout.status] link_effects: payout_claim: { none: Cancelling keeps the claim } emits: [PayoutCancelled] REOPEN_CLAIM: context: Claims doc: 'claims#reopen' doc_term: Reopen claim permission: keys: ['claims:reopen'] cite: { doc: 'claims#permissions', quote: Team leads reopen claims with claims:reopen } parameters: claim_id: { type: { ref: Claim }, cite: { doc: 'claims#reopen', quote: The team lead reopens claim_id when new damage is reported } } conditions: - id: claim_closed expr: { eq: [{ ref: claim_id.status }, { lit: CLOSED }] } cites: [{ cite: { doc: 'claims#reopen', quote: Only a CLOSED claim is reopened; a denied one goes to appeal } }] - id: within_window expr: { derived: { id: within_reopen_window, of: { ref: claim_id } } } cites: [{ cite: { doc: 'claims#reopen', quote: After the reopen window a new claim must be filed instead } }] scenarios: [CLM-09.S1] decision: hitPolicy: first rows: - when: { fails: claim_closed } result: REJECTED cites: [{ cite: { doc: 'claims#reopen', quote: Reopening a claim that is not closed is REJECTED } }] - when: { fails: within_window } result: REJECTED cites: [{ cite: { doc: 'claims#reopen', quote: Reopening after the window is REJECTED } }] otherwise: { result: APPLIED, cites: [{ cite: { doc: 'claims#reopen', quote: Otherwise the claim becomes REOPENED and waits for assignment; the reopening is APPLIED } }] } edits: [Claim.status] link_effects: claim_adjuster: unspecified: The reopen section does not say whether the claim keeps its adjuster cite: { doc: 'claims#reopen', quote: A reopened claim is handled like a new notice } claim_coverage: { none: Reopening keeps the coverage } assessment_claim: { none: Old assessments stay on the claim } reserve_claim: { none: Finance sets a new reserve after assessment } payout_claim: { none: Old payouts stay on the claim } fraud_review_claim: { none: Reopening does not refer } emits: [ClaimReopened]