# Synthetic Avouch example for Avouch Studio: a refund policy, and what the document leaves open. # All names and quotes are invented. The source is a short policy page and an FAQ that do not agree. # Where they are silent or disagree, the file says so (unspecified, unknown, knownSourceGaps) instead of picking an answer. formatVersion: 1 contexts: Orders: Purchases the customer made Support: Refund requests and their review Payments: Refunds and store credit permission_rows_not_commands: [] knownSourceGaps: - id: G1 rule: R12 kind: condition_unspecified keys: ['REVIEW_REQUEST:within_window', 'REVIEW_REQUEST:item_returned'] doc_line: 'policy#window; faq#how-long' conflict: The policy page gives 30 days to ask for a refund, the FAQ gives 14 days, and neither says when the item counts as returned proposed: Pick one refund window and use it on both pages; say which record shows that the item is back - id: G2 rule: R4 kind: precondition_reads_unspecified keys: ['REVIEW_REQUEST:item_returned'] doc_line: 'policy#returns' conflict: The policy pays a refund once the item is back, but names no record that shows the return proposed: Name the warehouse receipt, or another record, as the proof of return in policy#returns - id: G3 rule: R10 kind: permission_unknown keys: [GRANT_EXCEPTION] doc_line: 'policy#exceptions' conflict: The policy allows exceptions "at our discretion" but names no role that may grant one proposed: Name the role, and its permission key, that may grant an exception - id: G4 rule: R6 kind: effect_unspecified keys: ['ISSUE_REFUND:refund_store_credit'] doc_line: 'faq#store-credit' conflict: The FAQ says a refund can be paid as store credit, but not whether that opens a new credit or tops up an existing one proposed: State in faq#store-credit whether store credit is one balance per customer or one credit per refund dispositions: REJECTED: { class: rejected, cite: { doc: 'policy#results', quote: REJECTED means the request was not in a state to act on } } REQUEST_APPROVED: { class: applied, cite: { doc: 'policy#results', quote: REQUEST_APPROVED means the customer will get the money back } } REQUEST_DENIED: { class: applied, cite: { doc: 'policy#results', quote: REQUEST_DENIED means no refund is due } } MANAGER_REVIEW: { class: pending, cite: { doc: 'policy#exceptions', quote: MANAGER_REVIEW means a manager will look at the case } } REFUND_PAID: { class: applied, cite: { doc: 'policy#results', quote: REFUND_PAID means the money has been sent } } objectTypes: Purchase: context: Orders datasource: purchases doc: 'policy#purchases' properties: purchased_at: class: canonical type: timestamp cite: { doc: 'policy#window', quote: The refund window counts from the date of purchase } final_sale: class: unknown RefundRequest: context: Support datasource: refund_requests doc: 'policy#requests' properties: status: class: canonical type: enum cite: { doc: 'policy#requests', quote: We tell you the status of your request by email } reason: class: canonical type: enum cite: { doc: 'policy#requests', quote: Tell us why you want a refund } Refund: context: Payments datasource: refunds doc: 'policy#payment' properties: amount: class: canonical type: integer cite: { doc: 'policy#payment', quote: We refund the price you paid; shipping is not refunded } method: class: canonical type: enum cite: { doc: 'faq#store-credit', quote: You can choose your ORIGINAL_METHOD or STORE_CREDIT } StoreCredit: context: Payments datasource: store_credits doc: 'faq#store-credit' properties: balance: class: canonical type: integer cite: { doc: 'faq#store-credit', quote: Store credit can be spent on any later order } stateMachines: RefundRequest: doc: 'policy#requests' initial: SUBMITTED terminal: [PAID, DENIED] transitions: - { from: SUBMITTED, to: APPROVED, by: [REVIEW_REQUEST] } - { from: SUBMITTED, to: DENIED, by: [REVIEW_REQUEST] } - { from: SUBMITTED, to: NEEDS_REVIEW, by: [REVIEW_REQUEST] } - { from: NEEDS_REVIEW, to: APPROVED, by: [GRANT_EXCEPTION] } - { from: NEEDS_REVIEW, to: DENIED, by: [], out_of_scope: The policy does not say how a manager records a refusal; it is done by email today } - { from: APPROVED, to: PAID, by: [ISSUE_REFUND] } linkTypes: - { id: request_purchase, from: RefundRequest, to: Purchase, cardinality: 'N:1', via: purchase_id, doc: 'policy#requests' } - { id: refund_request, from: Refund, to: RefundRequest, cardinality: '1:1', via: request_id, doc: 'policy#payment' } - { id: refund_store_credit, from: Refund, to: StoreCredit, cardinality: 'N:1', via: store_credit_id, doc: 'faq#store-credit' } actionTypes: SUBMIT_REQUEST: context: Support doc: 'policy#requests' doc_term: Ask for a refund permission: none: Any customer can send the refund form cite: { doc: 'policy#requests', quote: Use the refund form on your order page } parameters: purchase_id: { type: { ref: Purchase }, cite: { doc: 'policy#requests', quote: The form is sent from the order page of purchase_id } } reason: { type: enum, cite: { doc: 'policy#requests', quote: Pick a reason from the list on the form } } conditions: [] creates: [RefundRequest] edits: [] link_effects: request_purchase: effect: The new request points to the purchase cite: { doc: 'policy#requests', quote: One request covers one order } refund_request: { none: No refund exists yet } emits: [] REVIEW_REQUEST: context: Support doc: 'policy#review' doc_term: Review request permission: keys: ['refunds:review'] cite: { doc: 'policy#review', quote: Support agents review requests with refunds:review } parameters: request_id: { type: { ref: RefundRequest }, cite: { doc: 'policy#review', quote: An agent opens request_id } } conditions: - id: request_submitted expr: { eq: [{ ref: request_id.status }, { lit: SUBMITTED }] } cites: [{ cite: { doc: 'policy#review', quote: A SUBMITTED request is reviewed once } }] - id: within_window unspecified: The policy page says 30 days and the FAQ says 14 days; this file does not choose reads: [Purchase.purchased_at] cites: - cite: { doc: 'policy#window', quote: Refunds are accepted within 30 days of purchase } - cite: { doc: 'faq#how-long', quote: You have 14 days to ask for your money back } - id: item_returned unspecified: The policy does not say how support knows the item came back reads: [] reads_unspecified: The policy names no record that shows the return cites: [{ cite: { doc: 'policy#returns', quote: We pay the refund once the item is back with us } }] decision: hitPolicy: first order: { cite: { doc: 'policy#review', quote: We check your request in this order } } rows: - when: { fails: request_submitted } result: REJECTED cites: [{ cite: { doc: 'policy#review', quote: A request we already answered is REJECTED } }] - when: { fails: within_window } result: REQUEST_DENIED cites: [{ cite: { doc: 'policy#window', quote: Late requests are REQUEST_DENIED } }] - when: { fails: item_returned } result: MANAGER_REVIEW cites: [{ cite: { doc: 'policy#exceptions', quote: 'If the item has not come back, the case goes to MANAGER_REVIEW' } }] next: { actions: [GRANT_EXCEPTION] } otherwise: { result: REQUEST_APPROVED, cites: [{ cite: { doc: 'policy#review', quote: Otherwise the request is REQUEST_APPROVED } }] } edits: [RefundRequest.status] link_effects: request_purchase: { none: Review keeps the purchase } refund_request: { none: Review does not pay } emits: [] GRANT_EXCEPTION: context: Support doc: 'policy#exceptions' doc_term: Grant exception permission: unknown parameters: request_id: { type: { ref: RefundRequest }, cite: { doc: 'policy#exceptions', quote: An exception is granted on request_id } } conditions: - id: request_in_review expr: { eq: [{ ref: request_id.status }, { lit: NEEDS_REVIEW }] } cites: [{ cite: { doc: 'policy#exceptions', quote: Exceptions are made only for a request in NEEDS_REVIEW } }] decision: hitPolicy: first rows: - when: { fails: request_in_review } result: REJECTED cites: [{ cite: { doc: 'policy#exceptions', quote: An exception for a request not under review is REJECTED } }] otherwise: { result: REQUEST_APPROVED, cites: [{ cite: { doc: 'policy#exceptions', quote: At our discretion a request may still be REQUEST_APPROVED } }] } edits: [RefundRequest.status] link_effects: request_purchase: { none: An exception keeps the purchase } refund_request: { none: An exception does not pay } emits: [] ISSUE_REFUND: context: Payments doc: 'policy#payment' doc_term: Pay refund permission: keys: ['refunds:pay'] cite: { doc: 'policy#payment', quote: Finance pays approved refunds with refunds:pay } parameters: request_id: { type: { ref: RefundRequest }, cite: { doc: 'policy#payment', quote: Finance pays the refund for request_id } } method: { type: enum, cite: { doc: 'faq#store-credit', quote: The customer picks the refund method } } conditions: - id: request_approved expr: { eq: [{ ref: request_id.status }, { lit: APPROVED }] } cites: [{ cite: { doc: 'policy#payment', quote: Only an APPROVED request is paid } }] decision: hitPolicy: first rows: - when: { fails: request_approved } result: REJECTED cites: [{ cite: { doc: 'policy#payment', quote: Paying a request that is not approved is REJECTED } }] otherwise: { result: REFUND_PAID, cites: [{ cite: { doc: 'policy#payment', quote: Otherwise the money goes out within 5 working days and the request is REFUND_PAID } }] } creates: [Refund] edits: [RefundRequest.status] crossContext: via: same_batch cite: { doc: 'policy#payment', quote: The request is marked paid when the refund is created } link_effects: refund_request: effect: The new refund points to the request it pays cite: { doc: 'policy#payment', quote: Each refund pays one request } refund_store_credit: unspecified: The FAQ does not say whether store credit opens a new credit or tops up an existing one cite: { doc: 'faq#store-credit', quote: We can refund you in store credit instead } request_purchase: { none: Paying keeps the purchase } emits: [RefundPaid]