jaz-clio 5.74.2 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +8 -8
  2. package/assets/skills/api/SKILL.md +3 -36
  3. package/assets/skills/cli/SKILL.md +18 -28
  4. package/assets/skills/cli/references/agent-gotchas.md +2 -2
  5. package/assets/skills/cli/references/command-catalog.md +15 -31
  6. package/assets/skills/cli/references/common-workflows.md +19 -28
  7. package/assets/skills/conversion/SKILL.md +1 -1
  8. package/assets/skills/jaz-kit/SKILL.md +1 -1
  9. package/assets/skills/jaz-kit/references/flows.md +2 -2
  10. package/assets/skills/jaz-pseudo-sql/SKILL.md +1 -1
  11. package/assets/skills/jobs/SKILL.md +42 -42
  12. package/assets/skills/jobs/references/audit-prep.md +8 -8
  13. package/assets/skills/jobs/references/bank-match.md +1 -1
  14. package/assets/skills/jobs/references/bank-recon.md +6 -6
  15. package/assets/skills/jobs/references/building-blocks.md +49 -30
  16. package/assets/skills/jobs/references/credit-control.md +13 -12
  17. package/assets/skills/jobs/references/document-collection.md +6 -6
  18. package/assets/skills/jobs/references/fa-review.md +28 -29
  19. package/assets/skills/jobs/references/gst-vat-filing.md +3 -3
  20. package/assets/skills/jobs/references/month-end-close.md +37 -33
  21. package/assets/skills/jobs/references/payment-run.md +3 -4
  22. package/assets/skills/jobs/references/quarter-end-close.md +20 -18
  23. package/assets/skills/jobs/references/supplier-recon.md +5 -5
  24. package/assets/skills/jobs/references/year-end-close.md +31 -21
  25. package/assets/skills/transaction-recipes/SKILL.md +54 -117
  26. package/assets/skills/transaction-recipes/references/accrued-expenses.md +86 -61
  27. package/assets/skills/transaction-recipes/references/asset-disposal.md +135 -93
  28. package/assets/skills/transaction-recipes/references/bad-debt-provision.md +87 -65
  29. package/assets/skills/transaction-recipes/references/bank-loan.md +104 -70
  30. package/assets/skills/transaction-recipes/references/building-blocks.md +168 -72
  31. package/assets/skills/transaction-recipes/references/capital-wip.md +9 -8
  32. package/assets/skills/transaction-recipes/references/declining-balance.md +91 -64
  33. package/assets/skills/transaction-recipes/references/deferred-revenue.md +105 -68
  34. package/assets/skills/transaction-recipes/references/dividend.md +100 -64
  35. package/assets/skills/transaction-recipes/references/employee-accruals.md +111 -73
  36. package/assets/skills/transaction-recipes/references/fixed-deposit.md +116 -63
  37. package/assets/skills/transaction-recipes/references/fx-revaluation.md +28 -19
  38. package/assets/skills/transaction-recipes/references/hire-purchase.md +45 -44
  39. package/assets/skills/transaction-recipes/references/ifrs16-lease.md +108 -73
  40. package/assets/skills/transaction-recipes/references/intercompany.md +8 -6
  41. package/assets/skills/transaction-recipes/references/prepaid-amortization.md +104 -65
  42. package/assets/skills/transaction-recipes/references/provisions.md +116 -64
  43. package/assets/templates/platform-rules/jaz-agent-rules.md +10 -9
  44. package/cli.mjs +529 -607
  45. package/package.json +1 -1
@@ -1,26 +1,27 @@
1
- # Recipe: Bad Debt / ECL Provision (engine name: `ecl`)
1
+ # Recipe: Bad Debt / ECL Provision (calculator type: `ecl`)
2
2
 
3
- > One-shot recipe for IFRS 9 simplified-approach ECL on trade receivables. Engine emits 1 journal: top-up (or reversal) of the existing Allowance for Doubtful Debts to match the per-bucket × loss-rate calculation. Run quarterly or annually (most SMBs); not monthly.
3
+ > One-shot recipe for IFRS 9 simplified-approach ECL on trade receivables. One journal: the top-up (or release) of the existing Allowance for Doubtful Debts to match the per-bucket × loss-rate calculation. Run quarterly or annually (most SMBs); not monthly. You calculate, create the capsule and post the journal yourself (see `building-blocks.md` § The three-step flow).
4
4
 
5
- ## Tools, recipes, calculators this recipe uses
5
+ ## Tools and calculator this recipe uses
6
6
 
7
- ### Recipe engine entry point
8
- - **`plan_recipe(recipe: 'ecl', ...)`**, used in step 2: returns RecipePlan with one journal: top-up amount (Dr Bad Debt Expense / Cr Allowance for Doubtful Debts) for the delta between calculated ECL and existing provision. If existing > calculated: reversal direction.
9
- - **`execute_recipe(recipe: 'ecl', ...)`**, used in step 4: posts the single ECL journal. ONE-SHOT: no schedule, no future-dated entries.
7
+ ### Calculator (offline, posts nothing)
8
+ - **MCP: `calculate(type: 'ecl', buckets, existingProvision, startDate, currency)`** (step 1). `buckets` is a list of `{ name, balance, rate }` with `rate` in percent; `startDate` is the provision date and dates the journal step.
9
+ - **CLI: `clio calc ecl --current <c> --30d <30> --60d <60> --90d <90> --120d <120> --rates <r1>,<r2>,<r3>,<r4>,<r5> --existing-provision <ep> --currency <code> --json`** (step 1): the same calculation over five fixed buckets. The CLI has no date flag, so its journal step is undated.
10
10
 
11
- ### Calculator (cross-check, no API key needed)
12
- - **`clio calc ecl --current <c> --30d <30> --60d <60> --90d <90> --120d <120> --rates <r1>,<r2>,<r3>,<r4>,<r5> --existing-provision <ep> --currency <code> --json`**, used in step 1: applies per-bucket loss rates to receivables aged into 5 buckets. Returns `{ totalReceivables, calculatedEcl, existingProvision, topUpRequired, perBucket: [{bucket, balance, lossRate, ecl}, ...] }`. Top-up positive = increase provision; negative = release / reverse.
11
+ ### Posting tools
12
+ - **`list_capsule_types` / `create_capsule_type(displayName: 'ECL Provision')` / `create_capsule(...)`** (step 3).
13
+ - **`create_journal(...)`** (step 4): the single ECL adjustment. ONE-SHOT: no schedule, no future-dated entries.
13
14
 
14
- ### Tools (jaz-api / direct)
15
- - **`generate_aged_ar(endDate: <date>)`**, step 1 input: pull AR aged into the same 5 buckets the calculator expects (current, 30d, 60d, 90d, 120d+).
16
- - **`search_accounts(filter: {name: {in: ['Allowance for Doubtful Debts', 'Bad Debt Expense']}})`**: step 3.
17
- - **`generate_trial_balance(endDate: <date>)`**, step 1 input: pull `existingProvision` from current `Allowance for Doubtful Debts` balance; step 5 verify post-journal balance matches calculated ECL.
18
- - **`search_capsules(filter: {title: {eq: <capsule.name>}})`**: step 0 idempotency check (one ECL capsule per period; quarterly = 4 per FY).
19
- - **`apply_credits_to_invoice(...)` / `create_customer_credit_note(...)`**, step 6 specific write-off pattern: when individual invoices are deemed unrecoverable, write them off via credit note OR direct payment with `paymentMethod: 'DEBT_WRITE_OFF'` (per memory rule).
15
+ ### Lookup and verification tools
16
+ - **`generate_aged_ar(endDate: <date>)`** (step 1 input): AR aged into the buckets the calculator expects.
17
+ - **`search_accounts(filter: {name: {in: ['Allowance for Doubtful Debts', 'Bad Debt Expense']}})`**: step 2.
18
+ - **`generate_trial_balance(endDate: <date>)`** (step 1 input): pull `existingProvision` from the current `Allowance for Doubtful Debts` balance; step 5 verify the post-journal balance matches the calculated ECL.
19
+ - **`search_capsules(filter: {title: {eq: <capsule title>}})`**: step 0 idempotency check (one ECL capsule per period; quarterly = 4 per FY).
20
+ - **`apply_credits_to_invoice(...)` / `create_customer_credit_note(...)`** (step 6, specific write-off pattern): when individual invoices are deemed unrecoverable, write them off via credit note OR direct payment with `paymentMethod: 'DEBT_WRITE_OFF'`.
20
21
 
21
22
  ### Cross-references
22
23
  - Operational context: invoked during year-end close (Y4 in `year-end-close.md`) for FY-end ECL; during the GST/VAT filing cycle if quarterly cadence is set; rarely during month-end close (mental check during variance review only).
23
- - Sibling: `provisions.md` (engine `provision`): IAS 37 provisions with PV unwinding pattern, more complex than this recipe.
24
+ - Sibling: `provisions.md` (calculator `provision`): IAS 37 provisions with PV unwinding pattern, more complex than this recipe.
24
25
  - IFRS / accounting context: IFRS 9.5.5.15 (simplified approach mandatory for trade receivables); IFRS 9.B5.5.35 (provision matrix). For specific large customers in stage-3 (objective evidence of impairment): supplement this recipe with specific impairment via `create_customer_credit_note` per customer.
25
26
 
26
27
  ---
@@ -35,18 +36,18 @@ search_capsules(filter: {title: {eq: 'FY2025 Year-End ECL True-Up'}})
35
36
 
36
37
  If a result returns: halt. ECL is one-shot per period; duplicate would double-recognize.
37
38
 
38
- ### Step 1: Pull AR aging + existing provision
39
+ ### Step 1: Pull AR aging + existing provision, then calculate
39
40
 
40
41
  ```
41
42
  generate_aged_ar(endDate: '2025-12-31')
42
43
  ```
43
44
 
44
45
  Returns aging buckets. Map to calculator inputs:
45
- - `current` (0-30d, not yet due or just due)
46
- - `30d` (31-60d)
47
- - `60d` (61-90d)
48
- - `90d` (91-120d)
49
- - `120d+` (over 120d)
46
+ - `current` (not yet overdue)
47
+ - `30d` (1-30 days overdue)
48
+ - `60d` (31-60 days overdue)
49
+ - `90d` (61-90 days overdue)
50
+ - `120d` (91+ days overdue)
50
51
 
51
52
  ```
52
53
  generate_trial_balance(endDate: '2025-12-31')
@@ -54,6 +55,22 @@ generate_trial_balance(endDate: '2025-12-31')
54
55
 
55
56
  Pull `balance['Allowance for Doubtful Debts']` (sign-flipped; it's a contra-asset, naturally credit balance). This is `existingProvision`.
56
57
 
58
+ ```
59
+ calculate(
60
+ type: 'ecl',
61
+ buckets: [
62
+ {name: 'Current', balance: 100000, rate: 0.5},
63
+ {name: '1-30 days', balance: 50000, rate: 2},
64
+ {name: '31-60 days', balance: 20000, rate: 5},
65
+ {name: '61-90 days', balance: 10000, rate: 10},
66
+ {name: '91+ days', balance: 5000, rate: 50}
67
+ ],
68
+ existingProvision: 5000,
69
+ currency: 'SGD',
70
+ startDate: '2025-12-31' // provision date: the aged AR report date. The ECL journal step is dated on it.
71
+ )
72
+ ```
73
+
57
74
  ```
58
75
  clio calc ecl \
59
76
  --current 100000 \
@@ -67,52 +84,58 @@ clio calc ecl \
67
84
  --json
68
85
  ```
69
86
 
70
- Returns: `{ totalReceivables: 185000, calculatedEcl: 5750, existingProvision: 5000, topUpRequired: 750, perBucket: [{bucket: 'current', balance: 100000, lossRate: 0.005, ecl: 500}, ...] }`. Top-up of $750 needed.
87
+ Returns `{ totalReceivables: 185000, totalEcl: 6000, weightedRate: 3.2432, adjustmentRequired: 1000, isIncrease: true, bucketDetails: [{ bucket: 'Current', balance: 100000, lossRate: 0.5, ecl: 500 }, ...], journal, blueprint }`. The bucket ECLs are 500 + 1,000 + 1,000 + 1,000 + 2,500 = 6,000; against the existing 5,000 a top-up of $1,000 is needed.
71
88
 
72
- `--rates` defaults: tune to the entity's historical loss rate. Common starting point for SMBs: `0.5,2,5,10,50` (%) for the 5 buckets. Auditor will sample-test the rates against actual historical losses; keep documentation of how rates were derived.
89
+ Rates are PERCENT: `0.5,2,5,10,50` means 0.5%, 2%, 5%, 10%, 50% (NOT 50%, 200%, 500%...). Tune them to the entity's historical loss rate. Common starting point for SMBs: `0.5,2,5,10,50` for the 5 buckets. Auditor will sample-test the rates against actual historical losses; keep documentation of how rates were derived.
73
90
 
74
- If `topUpRequired` is below the entity's materiality threshold: skip the recipe entirely; document the decision in your working notes ("ECL change immaterial: $X below threshold $Y").
91
+ `blueprint.steps` (single `journal`): Dr Bad Debt Expense 1,000 / Cr Allowance for Doubtful Debts 1,000.
75
92
 
76
- ### Step 2: Plan the recipe
93
+ If `adjustmentRequired` is negative (calculated ECL < existing provision; `isIncrease: false`): the journal direction reverses (Dr Allowance for Doubtful Debts / Cr Bad Debt Expense for the release).
77
94
 
78
- ```
79
- plan_recipe(
80
- recipe: 'ecl',
81
- buckets: [
82
- {name: 'Current', balance: 100000, rate: 0.5},
83
- {name: '1-30 days', balance: 50000, rate: 2},
84
- {name: '31-60 days', balance: 20000, rate: 5},
85
- {name: '61-90 days', balance: 10000, rate: 10},
86
- {name: '91+ days', balance: 5000, rate: 50}
87
- ],
88
- existingProvision: 5000,
89
- currency: 'SGD',
90
- startDate: '2025-12-31' // provision date: the aged AR report date. The ECL journal is dated on it.
91
- )
92
- ```
95
+ If `adjustmentRequired` is 0 there is nothing to post: `blueprint.steps` is empty. Stop here and record that the provision was reviewed and unchanged.
93
96
 
94
- Returns `RecipePlan` with `requiredAccounts: ['Allowance for Doubtful Debts', 'Bad Debt Expense']`, `needsContact: false`, `needsBankAccount: false`, `steps[1]` (single journal): Dr Bad Debt Expense 750 / Cr Allowance for Doubtful Debts 750.
97
+ If the adjustment is below the entity's materiality threshold: skip the posting entirely; document the decision in your working notes ("ECL change immaterial: $X below threshold $Y").
95
98
 
96
- If `topUpRequired` is negative (calculated ECL < existing provision): the journal direction reverses (Dr Allowance for Doubtful Debts / Cr Bad Debt Expense for the release).
99
+ ### Step 2: Resolve accounts
97
100
 
98
- ### Step 3: Resolve dependencies
99
-
100
- For each account in `requiredAccounts`:
101
- - `search_accounts(filter: {name: {eq: <accountName>}})`. Suggested classifications: `Allowance for Doubtful Debts` → `Current Asset` (contra-AR; sometimes set up as separate account, sometimes as a sub-account of `Accounts Receivable`); `Bad Debt Expense` → `Operating Expense`.
101
+ The blueprint's `Bad Debt Expense` and `Allowance for Doubtful Debts` are labels. Map each to the real account:
102
+ - `search_accounts(filter: {name: {in: ['Allowance for Doubtful Debts', 'Bad Debt Expense']}})`. Suggested classifications: `Allowance for Doubtful Debts` → `Current Asset` (contra-AR; sometimes set up as separate account, sometimes as a sub-account of `Accounts Receivable`); `Bad Debt Expense` → `Operating Expense`.
102
103
 
103
104
  If `Allowance for Doubtful Debts` doesn't exist in the CoA: `create_account(name: 'Allowance for Doubtful Debts', code: <unused account code>, accountType: 'Current Asset')` first. Common gap in CoAs that haven't run formal ECL.
104
105
 
105
- ### Step 4: Execute
106
+ No contact and no bank account are involved.
107
+
108
+ ### Step 3: Create the capsule
106
109
 
107
110
  ```
108
- execute_recipe(recipe: 'ecl', ...same args...) // accounts auto-resolved from CoA; pass `bankAccountName` / `contactName` for fuzzy resolve
111
+ list_capsule_types()
112
+ create_capsule(
113
+ capsuleTypeResourceId: <id of 'ECL Provision'>,
114
+ title: 'FY2025 Year-End ECL True-Up',
115
+ description: <blueprint.capsuleDescription>
116
+ )
109
117
  ```
110
118
 
111
- `startDate` is required: it dates the ECL journal, so pass the aged AR report date (`2025-12-31` here).
119
+ If `ECL Provision` is not in the list: `create_capsule_type(displayName: 'ECL Provision')` first.
120
+
121
+ ### Step 4: Post the journal
112
122
 
113
- When the calculated ECL equals `existingProvision` there is no adjustment: the plan has no steps and `execute_recipe` refuses with "Nothing to post" before creating anything.
123
+ Date it on the aged AR report date:
124
+
125
+ ```
126
+ create_journal(
127
+ valueDate: '2025-12-31',
128
+ reference: 'ECL-FY2025',
129
+ journalEntries: [
130
+ { accountResourceId: <Bad Debt Expense>, type: 'DEBIT', amount: 1000, description: 'ECL provision increase, IFRS 9 simplified approach' },
131
+ { accountResourceId: <Allowance for Doubtful Debts>, type: 'CREDIT', amount: 1000, description: 'ECL provision increase, IFRS 9 simplified approach' }
132
+ ],
133
+ saveAsDraft: true,
134
+ capsuleResourceId: <capsule id>
135
+ )
136
+ ```
114
137
 
115
- Returns: `{ capsule: {resourceId, type, title}, steps: [{step: 1, action: 'journal', status: 'created', resourceId: <journal id>}], summary: {total: 1, created: 1} }`. The single journal is DRAFT; finalize via `update_journal(resourceId: <id>, saveAsDraft: false)` once the practitioner confirms the inputs.
138
+ The journal is a DRAFT; finalize via `update_journal(resourceId: <id>, saveAsDraft: false)` once the practitioner confirms the inputs.
116
139
 
117
140
  ### Step 5: Verify
118
141
 
@@ -121,8 +144,8 @@ generate_trial_balance(endDate: '2025-12-31')
121
144
  ```
122
145
 
123
146
  Assert:
124
- - `balance['Allowance for Doubtful Debts'] == -calculatedEcl` (within 1 cent). Updated to match the new computed ECL.
125
- - `balance['Bad Debt Expense'] (period MTD) increased by topUpRequired` (or reduced if reversal direction).
147
+ - `balance['Allowance for Doubtful Debts'] == -totalEcl` (within 1 cent). Updated to match the new computed ECL.
148
+ - `balance['Bad Debt Expense'] (period MTD) increased by adjustmentRequired` (or reduced if it is a release).
126
149
  - `(balance['Accounts Receivable'] - |balance['Allowance for Doubtful Debts']|)` is the net receivables presented on the balance sheet (BS line: `Trade Receivables, net`).
127
150
 
128
151
  ### Step 6: Specific impairment (stage 3, separate from this recipe)
@@ -159,30 +182,29 @@ pay_invoice(
159
182
  )
160
183
  ```
161
184
 
162
- Per memory rule [PH IBO VAT proforma rule] and [Bank FX is Revaluation, not Realized]: use the appropriate jurisdiction-specific account if your CoA distinguishes write-offs from generic bad debt expense.
185
+ Use the appropriate jurisdiction-specific account if your CoA distinguishes write-offs from generic bad debt expense.
163
186
 
164
187
  Write-offs reduce both the gross AR balance AND offset against the existing Allowance (since the customer is now provisioned for). Re-run step 1 `generate_aged_ar` afterwards; the written-off customer should no longer appear, and the corresponding portion of the Allowance should reduce.
165
188
 
166
189
  ---
167
190
 
168
- ## Common error classes and recovery
191
+ ## Common problems and recovery
169
192
 
170
- | Source | Error | Recovery |
193
+ | Where | Problem | Recovery |
171
194
  |--------|-------|----------|
172
- | `plan_recipe` | 422 `unsupported_recipe` | File-name alias `bad-debt-provision` was used. Use canonical engine name `ecl`. |
173
- | `plan_recipe` | 422 `bucket_count_invalid` | Engine expects exactly 5 buckets: current, 30d, 60d, 90d, 120d+. Adjust input. |
174
- | `plan_recipe` | 422 `loss_rate_invalid` | Each rate must be 0-1 (decimal) OR 0-100 (percent). Engine accepts both; verify your --rates 0.5,2,5,10,50 means 0.5%, 2%, 5%, 10%, 50% (NOT 50%, 200%, 500%...). |
175
- | `execute_recipe` | 422 `account_not_found` for `Allowance for Doubtful Debts` | Step 3 incomplete. Most-commonly-missing account. Create via `create_account(name: 'Allowance for Doubtful Debts', code: <unused account code>, accountType: 'Current Asset')`. |
176
- | Verification | TB Allowance ≠ calculated ECL after journal posts | Investigate: likely an interim period had its own ECL recipe that wasn't reversed (cumulative). Audit via `generate_general_ledger(accountResourceIds: [<Allowance>], startDate: <FY-start>, endDate: <today>)`. |
177
- | Specific write-off changes ECL inputs | (process) | After Path A or Path B write-off, re-run step 1 `generate_aged_ar` and re-execute the ECL recipe with updated buckets; the calculated ECL likely reduces because the worst customer is now off the books. |
195
+ | Calculator | "... balance must be zero or positive" / "... loss rate must be zero or positive" | A bucket balance or rate is negative. A credit balance in an aging bucket is an unapplied receipt or credit note: resolve it in AR first, do not net it into the ECL. |
196
+ | Calculator | ECL far larger than expected | Rates were passed as percentages of 100 by mistake, or as decimals where percent is expected. `2` is 2%; `0.02` is 0.02%. |
197
+ | Step 2 | `Allowance for Doubtful Debts` is missing | Most-commonly-missing account. Create via `create_account(name: 'Allowance for Doubtful Debts', code: <unused account code>, accountType: 'Current Asset')`. |
198
+ | Verification | TB Allowance ≠ calculated ECL after journal posts | Investigate: likely an interim period posted its own ECL adjustment after `existingProvision` was read (cumulative). Audit via `generate_general_ledger(accountResourceIds: [<Allowance>], startDate: <FY-start>, endDate: <today>)`. |
199
+ | Specific write-off changes ECL inputs | (process) | After Path A or Path B write-off, re-run step 1 `generate_aged_ar` and recalculate with updated buckets; the calculated ECL likely reduces because the worst customer is now off the books. |
178
200
 
179
201
  ---
180
202
 
181
203
  ## Variations
182
204
 
183
- - **Quarterly cadence**: same recipe, run quarterly with `valueDate: <quarter-end>`. The review cadence (`monthly` | `quarterly` | `annual`) depends on the entity's policy. Most SMBs run annual (FY-end only) or quarterly.
205
+ - **Quarterly cadence**: same recipe, run quarterly with the journal dated `<quarter-end>`. The review cadence (`monthly` | `quarterly` | `annual`) depends on the entity's policy. Most SMBs run annual (FY-end only) or quarterly.
184
206
  - **Specific high-risk customer with stage-3 impairment**: combine simplified-approach ECL recipe (collective) + Path A or B specific write-off (individual). Run the collective AFTER the specific write-offs so the buckets reflect post-write-off balances.
185
- - **Multi-currency AR**: ECL is per-currency. Run the recipe per currency (each with its own `Allowance for Doubtful Debts (<currency>)` if you want segregation, or aggregate into one base-currency Allowance). Jaz auto-handles FX revaluation of the AR + Allowance balances per IAS 21.23 (do NOT invoke `fx-reval`).
207
+ - **Multi-currency AR**: ECL is per-currency. Run the recipe per currency (each with its own `Allowance for Doubtful Debts (<currency>)` if you want segregation, or aggregate into one base-currency Allowance). Jaz auto-handles FX revaluation of the AR + Allowance balances per IAS 21.23 (do NOT post an `fx-reval` result).
186
208
  - **Forward-looking macroeconomic adjustments** (IFRS 9 paragraphs B5.5.51-54): apply a multiplier to the `--rates` to reflect current/expected economic conditions. E.g., recession overlay: `--rates 1.0,3,7,15,60` instead of `0.5,2,5,10,50`. Document the rationale in your working notes.
187
209
  - **POCI assets** (purchased or originated credit-impaired): NOT supported by this simplified-approach recipe. Use stage-3 specific impairment via Path A/B for each.
188
210
 
@@ -194,4 +216,4 @@ Write-offs reduce both the gross AR balance AND offset against the existing Allo
194
216
  - GST/VAT filing cycle (where applicable): quarterly ECL review for entities on a quarterly cadence.
195
217
  - Month-end close: mental ECL cross-check during variance analysis only; formal recipe runs annually/quarterly.
196
218
  - `audit-prep.md` step 8: supporting schedule via the most recent `ECL Provision` capsule + the underlying `clio calc ecl` JSON. Auditor tests rate appropriateness against actual historical loss data.
197
- - Sibling `provisions.md` (engine `provision`): IAS 37 provisions with PV unwinding (more complex pattern).
219
+ - Sibling `provisions.md` (calculator `provision`): IAS 37 provisions with PV unwinding (more complex pattern).
@@ -1,27 +1,29 @@
1
- # Recipe: Bank Loan (engine name: `loan`)
1
+ # Recipe: Bank Loan (calculator type: `loan`)
2
2
 
3
- > Canonical recipe for term loans with fixed monthly installments. Always invoke the engine; never hand-build the amortization table or the 60+ payment journals.
3
+ > Canonical recipe for term loans with fixed monthly installments. Never hand-build the amortization table: the calculator returns it, with the journal lines for every installment. You create the capsule and post the disbursement and each repayment yourself (see `building-blocks.md` § The three-step flow).
4
4
 
5
- ## Tools, recipes, calculators this recipe uses
5
+ ## Tools and calculator this recipe uses
6
6
 
7
- ### Recipe engine entry point
8
- - **`plan_recipe(recipe: 'loan', ...)`** (used in step 2): returns `RecipePlan` with full amortization schedule, capsule shape, journal templates per period, required accounts.
9
- - **`execute_recipe(recipe: 'loan', ...)`** (used in step 4): posts the disbursement cash-in, creates the loan capsule, creates the monthly repayment scheduler (or per-period journals if `frequency: manual`).
7
+ ### Calculator (offline, posts nothing)
8
+ - **MCP: `calculate(type: 'loan', principal, annualRate, termMonths, startDate, currency)`** (step 1).
9
+ - **CLI: `clio calc loan --principal <p> --rate <annual %> --term <months> --start-date <YYYY-MM-DD> --currency <code> --json`** (step 1): the same result.
10
10
 
11
- ### Calculator (cross-check, no API key needed)
12
- - **`clio calc loan --principal <p> --rate <annual %> --term <months> --start-date <YYYY-MM-DD> --currency <code> --json`** (used in step 1): independently produce the amortization table and verify the engine's `perPeriodAmount`. Returns `{ perPeriodAmount, totalInterest, schedule[n] }`.
11
+ ### Posting tools
12
+ - **`list_capsule_types` / `create_capsule_type(displayName: 'Loan Repayment')` / `create_capsule(...)`** (step 3).
13
+ - **`create_cash_in(...)`** (step 4): the disbursement.
14
+ - **`create_journal(...)`** (step 4): one per repayment. The interest portion changes every month, so a fixed-amount schedule does not fit.
13
15
 
14
- ### Tools (jaz-api / direct)
15
- - **`list_bank_accounts()`** (used in step 3): resolve the disbursement target bank account by `name + currency` if the bank account resourceId isn't already known.
16
- - **`search_accounts(filter: {name: {in: ['Loan Payable', 'Interest Expense']}})`** (used in step 3): confirm liability + expense GL accounts exist.
17
- - **`search_capsules(filter: {title: {eq: <capsuleName>}})`** (used in step 0): detect duplicate setup before re-running. Loan capsules are unique per facility; duplicate creation is almost always an agent error.
18
- - **`generate_trial_balance(endDate: <date>)`** (used in step 5): verify the loan liability balance matches the schedule's `closingBalance` column.
19
- - **`update_journal(resourceId: <id>, saveAsDraft: false)`** (used in step 4 verification): lift draft journals to ACTIVE once practitioner confirms.
16
+ ### Lookup and verification tools
17
+ - **`search_capsules(filter: {title: {eq: <capsule title>}})`** (step 0): detect duplicate setup. Loan capsules are unique per facility; duplicate creation is almost always an agent error.
18
+ - **`list_bank_accounts()`** (step 2): resolve the disbursement bank account by `name + currency`.
19
+ - **`search_accounts(filter: {name: {in: ['Loan Payable', 'Interest Expense']}})`** (step 2): confirm liability + expense GL accounts exist.
20
+ - **`update_journal(resourceId: <id>, saveAsDraft: false)`** (step 5): lift a draft repayment journal to ACTIVE once the bank payment is confirmed.
21
+ - **`generate_trial_balance(endDate: <date>)`** (step 5): verify the loan liability balance matches the schedule's `closingBalance` column.
20
22
 
21
23
  ### Cross-references
22
- - Operational context: invoked during data migration (when the prior system's loan transfers in via the conversion clearing account, then forward-recognition starts here) and during month-end close (monthly accruals do NOT include loan interest; interest is auto-emitted by the loan scheduler).
24
+ - Operational context: invoked during data migration (when the prior system's loan transfers in via the conversion clearing account, then forward-recognition starts here) and during month-end close (monthly accruals do NOT include loan interest; each repayment journal from this recipe carries it).
23
25
  - Sibling recipes: `fixed-deposit.md` (mirror: placement instead of disbursement, interest income instead of expense), `hire-purchase.md` (loan + depreciation combo for asset purchases).
24
- - IFRS / accounting context: IFRS 9 amortized cost measurement. The engine uses effective interest method (constant rate × outstanding balance), not straight-line.
26
+ - IFRS / accounting context: IFRS 9 amortized cost measurement. The calculator uses the effective interest method (constant rate × outstanding balance), not straight-line.
25
27
 
26
28
  ---
27
29
 
@@ -30,25 +32,16 @@
30
32
  ### Step 0: Idempotency check
31
33
 
32
34
  ```
33
- search_capsules(filter: {title: {eq: 'Bank Loan — ABC Bank — 2025'}})
35
+ search_capsules(filter: {title: {eq: 'Bank Loan, ABC Bank, LN-2025-0042'}})
34
36
  ```
35
37
 
36
- If a result returns: halt and surface "Loan capsule `<name>` already exists (resourceId `<id>`). Re-running the recipe would create a duplicate disbursement. Confirm the practitioner intent: if extending an existing loan, use `update_capsule` not `execute_recipe`."
38
+ If a result returns: halt and surface "Loan capsule `<name>` already exists (resourceId `<id>`). Re-posting would create a duplicate disbursement. Confirm the practitioner intent: if this is the same facility, continue posting its remaining repayments into the existing capsule."
37
39
 
38
- ### Step 1: Independent cross-check (calculator)
40
+ ### Step 1: Calculate
39
41
 
40
42
  ```
41
- clio calc loan --principal 100000 --rate 6 --term 60 --start-date 2025-01-01 --currency SGD --json
42
- ```
43
-
44
- Returns: `{ perPeriodAmount: 1933.28, totalInterest: 15996.80, schedule: [{period, openingBalance, interest, principal, closingBalance}, ...] }`. Save to `workpapers/<period>/loan-amortization.json` for the workpaper record.
45
-
46
- ### Step 2: Plan the recipe
47
-
48
- ```
49
- plan_recipe(
50
- // Accounts, capsule and counterparty are not plan_recipe params: execute_recipe resolves accounts from the CoA and takes bankAccountName / contactName.
51
- recipe: 'loan',
43
+ calculate(
44
+ type: 'loan',
52
45
  principal: 100000,
53
46
  annualRate: 6,
54
47
  termMonths: 60,
@@ -57,47 +50,89 @@ plan_recipe(
57
50
  )
58
51
  ```
59
52
 
60
- Returns: `RecipePlan` with `requiredAccounts`, `needsContact: true`, `steps[0]` = disbursement cash-in, `steps[1..60]` = monthly repayment journals (template: 3-line entry; debit Loan Payable, debit Interest Expense, credit Cash). `capsule.contents` = `{ disbursementResourceId, schedulerResourceId, journalTemplate }`.
53
+ ```
54
+ clio calc loan --principal 100000 --rate 6 --term 60 --start-date 2025-01-01 --currency SGD --json
55
+ ```
61
56
 
62
- ### Step 3: Resolve dependencies
57
+ Returns `{ monthlyPayment: 1933.28, totalPayments: 115996.84, totalInterest: 15996.84, totalPrincipal: 100000, schedule: [{ period, date, openingBalance, payment, interest, principal, closingBalance, journal }, ...60], blueprint }`. Save it to `workpapers/<period>/loan-amortization.json` for the workpaper record.
63
58
 
64
- For every account in `requiredAccounts`:
65
- - `search_accounts(filter: {name: {eq: <accountName>}})`. If empty, halt: "Loan recipe references GL account `<accountName>` not in CoA. Create via `create_account` (suggested classifications: `Loan Payable` → `Non-current Liability`; `Interest Expense` → `Operating Expense`) or remap the account before retry."
59
+ `blueprint.steps` (61):
60
+ - Step 1, `cash-in`, dated `2025-01-01`: Dr Cash / Bank Account 100,000 / Cr Loan Payable 100,000.
61
+ - Steps 2 to 61, `journal`, dated `2025-02-01` through `2030-01-01`: Dr Loan Payable (principal portion), Dr Interest Expense (interest portion), Cr Cash / Bank Account (the installment). Month 1 is 1,433.28 principal + 500.00 interest = 1,933.28. The final installment is 1,933.32: it absorbs the rounding so the balance closes at exactly 0.
66
62
 
67
- If `bankAccountResourceId` resolution failed:
68
- - `list_bank_accounts()`, match by `name + currency`. If still no match: halt and surface it.
63
+ Without `startDate` the calculator returns the schedule only (`blueprint: null`). Set it to the drawdown date so the repayment dates match the bank's.
69
64
 
70
- For the lender contact:
71
- - `search_contacts(filter: {name: {eq: <vendor>}})`. If empty: halt and surface "Lender `<vendor>` not in Jaz contacts. Create as `supplier: true` via `create_contact` before retry."
65
+ ### Step 2: Resolve accounts and the bank account
72
66
 
73
- ### Step 4: Execute
67
+ The blueprint's `Loan Payable`, `Interest Expense` and `Cash / Bank Account` are labels. Map each to the real account:
68
+ - `search_accounts(filter: {name: {in: ['Loan Payable', 'Interest Expense']}})`. If one is missing, halt: "Loan recipe needs GL account `<accountName>`, which is not in the CoA. Create via `create_account` (suggested classifications: `Loan Payable` → `Non-current Liability`; `Interest Expense` → `Operating Expense`) or remap the account."
69
+ - `list_bank_accounts()`, match by `name + currency`. If no match: halt and surface it.
70
+
71
+ For the lender contact (optional, for the cash-in's `contactResourceId`):
72
+ - `search_contacts(filter: {name: {eq: <lender>}})`. If empty and the practitioner wants the lender recorded: create as `supplier: true` via `create_contact`.
73
+
74
+ ### Step 3: Create the capsule
74
75
 
75
76
  ```
76
- execute_recipe(recipe: 'loan', ...same args...) // accounts auto-resolved from CoA; pass `bankAccountName` / `contactName` for fuzzy resolve
77
+ list_capsule_types()
78
+ create_capsule(
79
+ capsuleTypeResourceId: <id of 'Loan Repayment'>,
80
+ title: 'Bank Loan, ABC Bank, LN-2025-0042',
81
+ description: <blueprint.capsuleDescription>
82
+ )
77
83
  ```
78
84
 
79
- Returns: `{ capsule: {resourceId, type, title}, steps: [{step, action, status, resourceId}, ...], summary: {total, created, ...} }`. The recipe creates **termMonths + 1 entries upfront**:
80
- - Step 1: 1 cash-in for the loan disbursement (per `jaz-api/SKILL.md` rule 26: `accountResourceId` at top level for the bank account, `lines: [{accountResourceId: <Loan Payable>, amount: 100000}]` for the offset). Posted ACTIVE immediately, whatever `finalize` says: cash entries have no draft state.
81
- - Steps 2..termMonths+1: **N future-dated DRAFT journals** (one per repayment period, dated end-of-month for each month from `<startDate>+1 month` through `<startDate>+termMonths`). Each is a 3-line entry: debit Loan Payable (principal portion per amortization schedule), debit Interest Expense (interest portion), credit Cash.
85
+ If `Loan Repayment` is not in the list: `create_capsule_type(displayName: 'Loan Repayment')` first.
82
86
 
83
- All N journals attach to the same capsule. They sit DRAFT until you finalize them, typically one per month during monthly-close after the actual bank payment posts.
87
+ ### Step 4: Post the entries
84
88
 
85
- Note: This is NOT the Jaz scheduler primitive. The recipe pre-emits all 60 journals as DRAFT for upfront capsule visibility (the auditor can see the full amortization). Practitioner alternative: skip the recipe and invoke `create_scheduled_journal(...)` directly with monthly cadence, but the recipe path is canonical for loans because the amortization schedule is non-fixed (interest portion changes each month) which scheduler templates don't handle natively.
89
+ **4a. Disbursement** (blueprint step 1). Per `jaz-api/SKILL.md` rule 26: `accountResourceId` at top level is the bank account; `lines` carries the offset.
86
90
 
87
- ### Step 5: Monthly action (during monthly-close)
91
+ ```
92
+ create_cash_in(
93
+ valueDate: '2025-01-01',
94
+ accountResourceId: <bank account>,
95
+ reference: 'LN-2025-0042-DISB',
96
+ lines: [{ accountResourceId: <Loan Payable>, amount: 100000, description: 'Loan proceeds, ABC Bank LN-2025-0042' }],
97
+ capsuleResourceId: <capsule id>
98
+ )
99
+ ```
100
+
101
+ It posts ACTIVE immediately: cash entries have no draft state. Post it once the funds have actually arrived. If the disbursement is already in the books (created from the bank feed), do not post it again: move it into the capsule with `move_transaction_capsules` if it sits in another capsule, or leave it and note its reference in the capsule description.
88
102
 
89
- After the actual bank payment posts each month, the corresponding repayment journal already exists in the capsule as DRAFT. Monthly close action:
103
+ **4b. Repayments** (blueprint steps 2 to 61). One `create_journal` per step, using that step's amounts:
90
104
 
91
105
  ```
92
- **STOP: not selectable by filter.** Journals carry no capsule or fixed-asset link in either direction (`JournalFilter` declares neither; a journal row has no such field even at `view: 'full'`; `GET /capsules/{id}` returns only a `totalTransactions` count, measured 2026-09-07). A date+status search returns every matching DRAFT in the org, so it must never feed `bulk_update_journals` or `delete_journal`. Surface the capsule and its expected count to the practitioner and let them identify the journals.
106
+ create_journal(
107
+ valueDate: '2025-02-01',
108
+ reference: 'LN-2025-0042-01',
109
+ journalEntries: [
110
+ { accountResourceId: <Loan Payable>, type: 'DEBIT', amount: 1433.28, description: 'Loan payment, month 1 of 60' },
111
+ { accountResourceId: <Interest Expense>, type: 'DEBIT', amount: 500.00, description: 'Loan payment, month 1 of 60' },
112
+ { accountResourceId: <bank account>, type: 'CREDIT', amount: 1933.28, description: 'Loan payment, month 1 of 60' }
113
+ ],
114
+ saveAsDraft: true,
115
+ capsuleResourceId: <capsule id>
116
+ )
93
117
  ```
94
118
 
95
- Returns the one DRAFT for that period (the engine pre-emitted it). Finalize:
119
+ Two workable cadences; agree one with the practitioner:
120
+ - **Post each month's journal at that month's close**, after the bank payment clears, from the saved schedule (`saveAsDraft: false`).
121
+ - **Post all 60 now as drafts** so the full amortization is visible in the capsule, then finalize one per month.
122
+
123
+ Either way the reference pattern (`LN-2025-0042-01` to `-60`) is what lets you find a specific month's journal later.
124
+
125
+ ### Step 5: Monthly action (during monthly-close)
126
+
127
+ After the actual bank payment posts each month, find that month's journal by its reference and finalize it (or post it now if you are posting month by month):
96
128
 
97
129
  ```
130
+ search_journals(filter: {reference: {eq: 'LN-2025-0042-03'}})
98
131
  update_journal(resourceId: <journal id>, saveAsDraft: false)
99
132
  ```
100
133
 
134
+ Journals cannot be filtered by capsule, and a date-plus-status search returns every matching DRAFT in the org: never feed one into `bulk_update_journals` or `delete_journal`.
135
+
101
136
  After disbursement (period 0):
102
137
  - `generate_trial_balance(endDate: <startDate>)`.
103
138
  - Assert: `balance['Cash / Bank Account']` increased by `principal`.
@@ -110,39 +145,38 @@ After each monthly finalize:
110
145
 
111
146
  After the FINAL period (60th repayment) is finalized:
112
147
  - Assert: `balance['Loan Payable'] == 0` exactly.
113
- - Assert: `balance['Interest Expense'] (life-to-date)` matches `totalInterest` from the calculator within ±1 cent (engine forces final-period adjustment for rounding).
114
- - Close the capsule via a manual `update_capsule(title: '<original> [CLOSED]')` (the API has no `status` field for capsules; closure is informational only) if the org tracks capsule status.
148
+ - Assert: `balance['Interest Expense'] (life-to-date)` matches `totalInterest` from the calculator (the final period carries the rounding adjustment).
149
+ - Close the capsule via a manual `update_capsule(resourceId: <id>, title: '<original> [CLOSED]')` (the API has no `status` field for capsules; closure is informational only) if the org tracks capsule status.
115
150
 
116
151
  ---
117
152
 
118
- ## Common error classes and recovery
153
+ ## Common problems and recovery
119
154
 
120
- | Source | Error | Recovery |
155
+ | Where | Problem | Recovery |
121
156
  |--------|-------|----------|
122
- | `plan_recipe` | 422 `unsupported_recipe` | File-name alias `bank-loan` was used. Use canonical engine name `loan`. |
123
- | `plan_recipe` | 422 `term_too_short` (`termMonths < 2`) | Term loans must be ≥2 periods. For single-shot principal-plus-interest, model as `accrued-expense` for the interest leg + manual journal for principal repayment. |
124
- | `execute_recipe` | 422 `bank_account_not_found` | Step 3 resolution stale. Re-run `list_bank_accounts` and re-resolve the bank account resourceId. |
125
- | `execute_recipe` | 422 `currency_mismatch_bank_account` | Loan currency ≠ bank account currency. Either pass a `currencyAccount` for FX-on-disbursement, or pick a bank account in the loan's source currency (per `jaz-api/SKILL.md` rule 24). |
126
- | `execute_recipe` | 409 `capsule_already_exists` | Duplicate setup. Step 0 idempotency check should have caught this; go back to step 0. |
127
- | Scheduler | Repayment journal posts but interest amount is off by cents | Engine uses effective interest method per period; if the entity's materiality threshold is below 1 cent, narrow the assertion. Otherwise expected behavior. |
128
- | Scheduler | Repayment journal does NOT post on expected date | The schedule may have been set INACTIVE (`update_scheduled_journal(status: 'INACTIVE')`). Look for this period's repayment journal (journals cannot be filtered by capsule: check each candidate with `get_journal` (its `capsule.resourceId`) and confirm the set with the practitioner); if none, check scheduler status. Resume or document the pause in your working notes. |
129
- | `update_capsule` | 422 `capsule_locked` | The capsule is in a closed period (lock date passed). Lift the lock first via `update_account` lock_date OR add the new entry in the next open period. |
157
+ | Calculator | "Principal must be a positive number" / "Term (months) must be a positive integer" | Fix the input. For a single-shot principal-plus-interest loan (one period), a schedule adds nothing: post the interest as an accrual and the principal repayment as a manual journal. |
158
+ | Step 2 | Bank account not found | Re-run `list_bank_accounts` and re-resolve the bank account resourceId. |
159
+ | `create_cash_in` | Loan currency ≠ bank account currency | Pick a bank account in the loan's currency, or record the FX on disbursement (per `jaz-api/SKILL.md` rule 24). |
160
+ | `create_capsule` | Returns the existing capsule instead of a new one | Duplicate setup. Step 0 should have caught this; go back to step 0. |
161
+ | Verification | Interest amount off by cents against the bank's statement | The calculator uses the effective interest method per period, rounded to 2dp. If the bank's own schedule differs by cents, post the bank's figures: the bank's statement is the record. |
162
+ | Monthly finalize | Journal falls in a locked period | The lock date has passed. Lift the lock first, or post the entry in the next open period, with the practitioner's agreement. |
163
+ | A step failed midway | Disbursement posted, some repayments not | Do not start again: `search_journals` by reference to see which months exist, then continue from the first missing one. |
130
164
 
131
165
  ---
132
166
 
133
167
  ## Variations
134
168
 
135
- - **Variable-rate loan:** Cannot model in a single `plan_recipe` call. Run the recipe for the initial fixed period; when the rate changes, halt the existing schedule (`update_scheduled_journal(resourceId: <scheduler id>, status: 'INACTIVE')`; `PAUSED` is rejected with 422), recompute with new rate via `clio calc loan` from the current outstanding balance, and run `plan_recipe` + `execute_recipe` again with the new schedule, passing `existingTxnId: <original disbursement id>` so the engine skips re-posting the disbursement. The engine files the new repayments under a new capsule; to keep one capsule per facility, move them with `move_transaction_capsules(businessTransactionResourceIds, oldCapsuleResourceId: <new capsule>, newCapsuleResourceId: <original capsule>)`.
136
- - **Lump-sum principal repayment:** Post a manual journal (`create_journal`) Dr Loan Payable / Cr Cash. Then halt the existing scheduler and re-plan with the new outstanding balance.
137
- - **Interest-only period:** Not supported by the loan calculator. Workaround: post N manual interest-only journals via `create_journal` (Dr Interest Expense / Cr Cash) for the interest-only window, then run `plan_recipe(recipe: 'loan', ...)` from the start of the amortizing window with the full outstanding principal.
138
- - **Multi-currency loan (USD loan with SGD base):** Pass `currency: 'USD'`. Disbursement records via `currency: { sourceCurrency: 'USD' }` per `jaz-api/SKILL.md` rule 25. Monthly repayments stay in USD. Period-end FX revaluation against base currency is auto-handled by Jaz (Loan Payable is a monetary item per IAS 21.23; Jaz auto-translates at closing rate). Verify via the month-end close FX verification flow; do NOT invoke `execute_recipe(recipe: 'fx-reval', ...)`.
139
- - **Loan origination fees:** Out of scope for this recipe (the engine's IFRS 9 effective-interest treatment doesn't currently amortize fees into the EIR). Post fees as a separate manual journal: Dr `Operating Expense > Loan Origination Fee` / Cr Cash. For IFRS 9 EIR-amortized fees, model the fee as `prepaid-expense` over the loan term.
140
- - **Year-end current/non-current reclassification:** Out of scope for the engine; manual annual journal: Dr Loan Payable Non-current / Cr Loan Payable Current for the next 12 months' principal portion. Job blueprint `jobs/references/year-end-close.md` Y6 covers this.
169
+ - **Variable-rate loan:** One calculation covers one fixed rate. When the rate changes, delete the remaining DRAFT repayment journals (each found by its reference, then `delete_journal(resourceId: <id>)`), recalculate from the current outstanding balance with the new rate (`principal: <outstanding>`, `termMonths: <remaining>`), and post the new repayment journals into the SAME capsule. Skip the new blueprint's `cash-in` step: the disbursement is already in the books.
170
+ - **Lump-sum principal repayment:** Post a manual journal (`create_journal`) Dr Loan Payable / Cr Cash. Then replace the remaining repayments as for a rate change, from the new outstanding balance.
171
+ - **Interest-only period:** Not supported by the loan calculator. Workaround: post N manual interest-only journals via `create_journal` (Dr Interest Expense / Cr Cash) for the interest-only window, then calculate from the start of the amortizing window with the full outstanding principal.
172
+ - **Multi-currency loan (USD loan with SGD base):** Pass `currency: 'USD'`. Disbursement records via `currency: { sourceCurrency: 'USD' }` per `jaz-api/SKILL.md` rule 25. Monthly repayments stay in USD. Period-end FX revaluation against base currency is auto-handled by Jaz (Loan Payable is a monetary item per IAS 21.23; Jaz auto-translates at closing rate). Verify via the month-end close FX verification flow; do NOT post an `fx-reval` result.
173
+ - **Loan origination fees:** Out of scope for the calculator (its effective-interest schedule does not amortize fees into the EIR). Post fees as a separate manual journal: Dr `Operating Expense > Loan Origination Fee` / Cr Cash. For IFRS 9 EIR-amortized fees, model the fee as `prepaid-expense` over the loan term.
174
+ - **Year-end current/non-current reclassification:** Not part of the schedule; manual annual journal: Dr Loan Payable Non-current / Cr Loan Payable Current for the next 12 months' principal portion. Job playbook `jobs/references/year-end-close.md` Y6 covers this.
141
175
 
142
176
  ---
143
177
 
144
178
  ## Cross-references
145
179
 
146
- - Month-end close: explicitly excludes loan interest from monthly accruals because the loan scheduler emits it automatically. Never post a manual loan-interest accrual.
147
- - `jobs/references/year-end-close.md` Y6: current/non-current reclassification of the next 12 months' principal portion (manual journal pattern, not engine-managed).
148
- - Data migration: when the prior system carried a loan, the opening trial balance includes the outstanding balance. Conversion (`jaz-conversion/SKILL.md § Option 2`) loads it via the `Conversion Clearing > Loan` account; this recipe then runs from the migration date forward only (do NOT model historical periods retroactively).
180
+ - Month-end close: explicitly excludes loan interest from monthly accruals because each month's repayment journal from this recipe already carries the interest. Never post a separate loan-interest accrual on top of it.
181
+ - `jobs/references/year-end-close.md` Y6: current/non-current reclassification of the next 12 months' principal portion (manual journal pattern).
182
+ - Data migration: when the prior system carried a loan, the opening trial balance includes the outstanding balance. Conversion (`jaz-conversion/SKILL.md § Option 2`) loads it via the `Conversion Clearing > Loan` account; this recipe then runs from the migration date forward only (do NOT model historical periods retroactively), and the blueprint's `cash-in` step is skipped.