@dizzlkheinz/ynab-mcpb 0.16.0 → 0.17.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.
- package/.code/agents/0098661e-0fa3-4990-beb9-c0cbf3f123aa/status.txt +1 -0
- package/.code/agents/1324/exec-call_tIpx9uV1TpARbAMZonRQm8AO.txt +757 -0
- package/.code/agents/1572/exec-call_GjVFBFOWcY7lE0idc5nWlLNh.txt +781 -0
- package/.code/agents/1846/exec-call_1YNAVD18RjrMN7JnfkkQhUP3.txt +766 -0
- package/.code/agents/1846/exec-call_lh3lDzE4WJAh1lFiomiiZ73D.txt +766 -0
- package/.code/agents/2038/exec-call_DYwOukaYsL8VCONWmV2rUW5u.txt +766 -0
- package/.code/agents/2038/exec-call_c7fOQ7UrpVcTtvdfGBRM146V.txt +652 -0
- package/.code/agents/2038/exec-call_ySNyq9Mm55jWE480s54r5QcA.txt +766 -0
- package/.code/agents/2256/exec-call_AtPcRWPmFPMcmX6qOFm1fCEY.txt +766 -0
- package/.code/agents/2454/exec-call_aFJpupwjfZeOBm7ixI5Vc8z2.txt +766 -0
- package/.code/agents/2454/exec-call_wogZ4HfXTodTEXvdgXlVUBpv.txt +766 -0
- package/.code/agents/2e905864-aa07-4314-bcf9-c5b32277e4ac/result.txt +36 -0
- package/.code/agents/3073/exec-call_Peeagc9DxGYLgE6pNdMZhqIE.txt +766 -0
- package/.code/agents/3073/exec-call_d2YSE3hXF08KRSoUM3qd8Z3x.txt +766 -0
- package/.code/agents/335aa031-466d-4fb7-925f-3cd864e264d0/result.txt +191 -0
- package/.code/agents/3364/exec-call_NbhIrsM5HhyDZDmJZG5CuCYL.txt +766 -0
- package/.code/agents/3364/exec-call_cKtJg0NrXiwXEFwlsE3uPZRA.txt +766 -0
- package/.code/agents/36d98414-5cde-4d9d-9a67-a240a18c1f07/result.txt +189 -0
- package/.code/agents/4604e866-b7b8-44f5-992f-2f683b0a523b/status.txt +1 -0
- package/.code/agents/5f8dc01c-47b3-4163-b0b3-aa31be89fcdc/status.txt +1 -0
- package/.code/agents/7/exec-call_HltHpkDox0Zm1vGEjdksUgpE.txt +1120 -0
- package/.code/agents/7/exec-call_LCATrOPPAgbxW9Q1z0XaVi2E.txt +2646 -0
- package/.code/agents/7/exec-call_W8DeRfNG9hvbgVFvf0clBf6R.txt +2646 -0
- package/.code/agents/94a0ddf3-a304-4ec3-913e-3cceef509948/error.txt +1 -0
- package/.code/agents/e2c752b7-711d-423a-af57-f53c809deb84/result.txt +160 -0
- package/.code/agents/e6601719-c31f-4a0e-8c71-d70787d0ab71/status.txt +1 -0
- package/.code/agents/f250b7ed-5bd5-4036-aa8c-ce63caee7d61/result.txt +20 -0
- package/AGENTS.md +1 -36
- package/CLAUDE.md +131 -51
- package/NUL +0 -1
- package/README.md +27 -14
- package/dist/bundle/index.cjs +41 -41
- package/dist/server/YNABMCPServer.js +28 -381
- package/dist/server/config.d.ts +2 -0
- package/dist/server/config.js +1 -0
- package/dist/tools/accountTools.d.ts +2 -0
- package/dist/tools/accountTools.js +45 -0
- package/dist/tools/adapters.d.ts +12 -0
- package/dist/tools/adapters.js +25 -0
- package/dist/tools/budgetTools.d.ts +2 -0
- package/dist/tools/budgetTools.js +30 -0
- package/dist/tools/categoryTools.d.ts +2 -0
- package/dist/tools/categoryTools.js +45 -0
- package/dist/tools/monthTools.d.ts +2 -0
- package/dist/tools/monthTools.js +32 -0
- package/dist/tools/payeeTools.d.ts +2 -0
- package/dist/tools/payeeTools.js +32 -0
- package/dist/tools/reconciliation/index.d.ts +2 -0
- package/dist/tools/reconciliation/index.js +33 -0
- package/dist/tools/schemas/common.d.ts +3 -0
- package/dist/tools/schemas/common.js +3 -0
- package/dist/tools/schemas/outputs/comparisonOutputs.d.ts +1 -1
- package/dist/tools/transactionTools.d.ts +2 -0
- package/dist/tools/transactionTools.js +129 -0
- package/dist/tools/utilityTools.d.ts +3 -1
- package/dist/tools/utilityTools.js +32 -2
- package/dist/types/index.d.ts +1 -0
- package/dist/types/toolRegistration.d.ts +27 -0
- package/dist/types/toolRegistration.js +1 -0
- package/package.json +2 -2
- package/scripts/run-domain-integration-tests.js +4 -1
- package/src/__tests__/workflows.e2e.test.ts +1 -7
- package/src/server/YNABMCPServer.ts +33 -519
- package/src/server/__tests__/toolRegistration.test.ts +236 -0
- package/src/server/config.ts +1 -0
- package/src/tools/__tests__/adapters.test.ts +113 -0
- package/src/tools/__tests__/transactionTools.test.ts +90 -17
- package/src/tools/__tests__/utilityTools.test.ts +7 -7
- package/src/tools/accountTools.ts +53 -0
- package/src/tools/adapters.ts +74 -0
- package/src/tools/budgetTools.ts +37 -0
- package/src/tools/categoryTools.ts +53 -0
- package/src/tools/monthTools.ts +39 -0
- package/src/tools/payeeTools.ts +39 -0
- package/src/tools/reconciliation/index.ts +45 -0
- package/src/tools/schemas/common.ts +18 -0
- package/src/tools/transactionTools.ts +150 -0
- package/src/tools/utilityTools.ts +42 -2
- package/src/types/index.ts +3 -0
- package/src/types/toolRegistration.ts +88 -0
- package/.dxtignore +0 -57
- package/.github/workflows/pr-description-check.yml +0 -88
- package/CODEREVIEW_RESPONSE.md +0 -128
- package/SCHEMA_IMPROVEMENT_SUMMARY.md +0 -120
- package/TESTING_NOTES.md +0 -217
- package/accountactivity-merged.csv +0 -149
- package/bundle-analysis.html +0 -13110
- package/docs/README.md +0 -72
- package/docs/getting-started/CONFIGURATION.md +0 -175
- package/docs/getting-started/INSTALLATION.md +0 -333
- package/docs/getting-started/QUICKSTART.md +0 -282
- package/docs/guides/ARCHITECTURE.md +0 -533
- package/docs/guides/DEPLOYMENT.md +0 -189
- package/docs/guides/INTEGRATION_TESTING.md +0 -730
- package/docs/guides/TESTING.md +0 -591
- package/docs/plans/2025-11-20-reloadable-config-token-validation.md +0 -93
- package/docs/plans/2025-11-21-fix-transaction-cached-property.md +0 -362
- package/docs/plans/2025-11-21-reconciliation-error-handling.md +0 -90
- package/docs/plans/2025-11-21-v014-hardening.md +0 -153
- package/docs/plans/reconciliation-v2-redesign.md +0 -1571
- package/docs/reconciliation-flow.md +0 -83
- package/docs/reference/EXAMPLES.md +0 -946
- package/docs/reference/TOOLS.md +0 -348
- package/docs/reference/TROUBLESHOOTING.md +0 -481
- package/fix-types.sh +0 -17
- package/test-csv-sample.csv +0 -28
- package/test-exports/sample_bank_statement.csv +0 -7
- package/test-reconcile-autodetect.js +0 -40
- package/test-reconcile-tool.js +0 -152
- package/test-reconcile-with-csv.cjs +0 -89
- package/test-statement.csv +0 -8
- package/test_debug.js +0 -47
- package/test_mcp_tools.mjs +0 -75
- package/test_simple.mjs +0 -16
|
@@ -1,362 +0,0 @@
|
|
|
1
|
-
# Fix Missing `cached` Property in Large Transaction Responses
|
|
2
|
-
|
|
3
|
-
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
4
|
-
|
|
5
|
-
**Goal:** Fix GitHub Action test failure by adding the missing `cached` property to large transaction list responses.
|
|
6
|
-
|
|
7
|
-
**Architecture:** The `handleListTransactions` function in `transactionTools.ts` has two response paths: normal (lines 815+) and large response (lines 788-812). The large response path is missing the `cached` and `cache_info` properties that the normal path includes, causing test assertion failures when transaction data exceeds 90KB.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** TypeScript, Vitest, YNAB API integration tests
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Background
|
|
14
|
-
|
|
15
|
-
**Current Issue:**
|
|
16
|
-
- GitHub Action failing: `src/tools/__tests__/accountTools.delta.integration.test.ts:94`
|
|
17
|
-
- Error: `expected undefined to be false // Object.is equality`
|
|
18
|
-
- Test code: `expect(firstPayload.cached).toBe(false);`
|
|
19
|
-
|
|
20
|
-
**Root Cause:**
|
|
21
|
-
File `src/tools/transactionTools.ts` has two response code paths:
|
|
22
|
-
1. **Large response path** (lines 788-812): When transactions > 90KB, returns preview + summary
|
|
23
|
-
2. **Normal path** (lines 815+): Returns full transaction list
|
|
24
|
-
|
|
25
|
-
The large response path returns an object WITHOUT the `cached` property.
|
|
26
|
-
The normal path returns an object WITH `cached: cacheHit` and `cache_info`.
|
|
27
|
-
|
|
28
|
-
**Test accounts with many transactions trigger the large response path, causing `cached` to be undefined.**
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## Task 1: Add Unit Test Coverage for Large Response Path
|
|
33
|
-
|
|
34
|
-
**Files:**
|
|
35
|
-
- Read: `src/tools/__tests__/transactionTools.test.ts`
|
|
36
|
-
- Modify: `src/tools/__tests__/transactionTools.test.ts` (add test after existing tests)
|
|
37
|
-
|
|
38
|
-
**Step 1: Read the existing test file to understand patterns**
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
cat src/tools/__tests__/transactionTools.test.ts | head -100
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Expected: See test structure, mocking patterns, imports
|
|
45
|
-
|
|
46
|
-
**Step 2: Write failing test for large response cached property**
|
|
47
|
-
|
|
48
|
-
Add this test to `src/tools/__tests__/transactionTools.test.ts` in the appropriate describe block:
|
|
49
|
-
|
|
50
|
-
```typescript
|
|
51
|
-
it('should include cached property in large response path', async () => {
|
|
52
|
-
// Create large transaction list (> 90KB)
|
|
53
|
-
const largeTransactionList: ynab.TransactionDetail[] = [];
|
|
54
|
-
for (let i = 0; i < 5000; i++) {
|
|
55
|
-
largeTransactionList.push({
|
|
56
|
-
id: `transaction-${i}`,
|
|
57
|
-
date: '2025-01-01',
|
|
58
|
-
amount: -10000,
|
|
59
|
-
memo: 'Test transaction with long memo to increase size '.repeat(10),
|
|
60
|
-
cleared: 'cleared',
|
|
61
|
-
approved: true,
|
|
62
|
-
flag_color: null,
|
|
63
|
-
account_id: 'test-account',
|
|
64
|
-
payee_id: null,
|
|
65
|
-
category_id: null,
|
|
66
|
-
transfer_account_id: null,
|
|
67
|
-
transfer_transaction_id: null,
|
|
68
|
-
matched_transaction_id: null,
|
|
69
|
-
import_id: null,
|
|
70
|
-
import_payee_name: null,
|
|
71
|
-
import_payee_name_original: null,
|
|
72
|
-
debt_transaction_type: null,
|
|
73
|
-
deleted: false,
|
|
74
|
-
account_name: 'Test Account',
|
|
75
|
-
payee_name: 'Test Payee',
|
|
76
|
-
category_name: 'Test Category',
|
|
77
|
-
subtransactions: [],
|
|
78
|
-
} as ynab.TransactionDetail);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const mockDeltaFetcher = {
|
|
82
|
-
fetchTransactionsByAccount: vi.fn().mockResolvedValue({
|
|
83
|
-
data: largeTransactionList,
|
|
84
|
-
wasCached: false,
|
|
85
|
-
usedDelta: false,
|
|
86
|
-
}),
|
|
87
|
-
} as unknown as DeltaFetcher;
|
|
88
|
-
|
|
89
|
-
const result = await handleListTransactions(mockYnabAPI, mockDeltaFetcher, {
|
|
90
|
-
budget_id: 'test-budget',
|
|
91
|
-
account_id: 'test-account',
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
const content = result.content?.[0];
|
|
95
|
-
expect(content).toBeDefined();
|
|
96
|
-
expect(content?.type).toBe('text');
|
|
97
|
-
|
|
98
|
-
const parsedResponse = JSON.parse(content!.text);
|
|
99
|
-
|
|
100
|
-
// Should have cached property even in large response path
|
|
101
|
-
expect(parsedResponse.cached).toBeDefined();
|
|
102
|
-
expect(parsedResponse.cached).toBe(false);
|
|
103
|
-
expect(parsedResponse.cache_info).toBeDefined();
|
|
104
|
-
});
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
**Step 3: Run the test to verify it fails**
|
|
108
|
-
|
|
109
|
-
```bash
|
|
110
|
-
npm run test:unit -- src/tools/__tests__/transactionTools.test.ts -t "should include cached property in large response path"
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
Expected: FAIL with error about `cached` being undefined
|
|
114
|
-
|
|
115
|
-
**Step 4: Commit the failing test**
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
git add src/tools/__tests__/transactionTools.test.ts
|
|
119
|
-
git commit -m "test: add failing test for cached property in large transaction responses"
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
## Task 2: Fix Large Response Path to Include Cached Property
|
|
125
|
-
|
|
126
|
-
**Files:**
|
|
127
|
-
- Modify: `src/tools/transactionTools.ts:788-812`
|
|
128
|
-
|
|
129
|
-
**Step 1: Read the current large response code**
|
|
130
|
-
|
|
131
|
-
```bash
|
|
132
|
-
cat src/tools/transactionTools.ts | sed -n '788,812p'
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
Expected: See the current implementation missing `cached` and `cache_info`
|
|
136
|
-
|
|
137
|
-
**Step 2: Add cached properties to large response**
|
|
138
|
-
|
|
139
|
-
In `src/tools/transactionTools.ts`, replace lines 788-812 with:
|
|
140
|
-
|
|
141
|
-
```typescript
|
|
142
|
-
if (estimatedSize > sizeLimit) {
|
|
143
|
-
// Return summary and suggest export
|
|
144
|
-
const preview = transactions.slice(0, 50);
|
|
145
|
-
return {
|
|
146
|
-
content: [
|
|
147
|
-
{
|
|
148
|
-
type: 'text',
|
|
149
|
-
text: responseFormatter.format({
|
|
150
|
-
message: `Found ${transactions.length} transactions (${Math.round(estimatedSize / 1024)}KB). Too large to display all.`,
|
|
151
|
-
suggestion: "Use 'export_transactions' tool to save all transactions to a file.",
|
|
152
|
-
showing: `First ${preview.length} transactions:`,
|
|
153
|
-
total_count: transactions.length,
|
|
154
|
-
estimated_size_kb: Math.round(estimatedSize / 1024),
|
|
155
|
-
cached: cacheHit,
|
|
156
|
-
cache_info: cacheHit
|
|
157
|
-
? `Data retrieved from cache for improved performance${usedDelta ? ' (delta merge applied)' : ''}`
|
|
158
|
-
: 'Fresh data retrieved from YNAB API',
|
|
159
|
-
preview_transactions: preview.map((transaction) => ({
|
|
160
|
-
id: transaction.id,
|
|
161
|
-
date: transaction.date,
|
|
162
|
-
amount: milliunitsToAmount(transaction.amount),
|
|
163
|
-
memo: transaction.memo,
|
|
164
|
-
payee_name: transaction.payee_name,
|
|
165
|
-
category_name: transaction.category_name,
|
|
166
|
-
})),
|
|
167
|
-
}),
|
|
168
|
-
},
|
|
169
|
-
],
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
**Changes:**
|
|
175
|
-
- Added `cached: cacheHit,` after `estimated_size_kb`
|
|
176
|
-
- Added `cache_info` with same pattern as normal response path
|
|
177
|
-
|
|
178
|
-
**Step 3: Run unit tests to verify fix**
|
|
179
|
-
|
|
180
|
-
```bash
|
|
181
|
-
npm run test:unit -- src/tools/__tests__/transactionTools.test.ts -t "should include cached property in large response path"
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
Expected: PASS
|
|
185
|
-
|
|
186
|
-
**Step 4: Run all transaction tool tests**
|
|
187
|
-
|
|
188
|
-
```bash
|
|
189
|
-
npm run test:unit -- src/tools/__tests__/transactionTools.test.ts
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
Expected: All tests PASS
|
|
193
|
-
|
|
194
|
-
**Step 5: Commit the fix**
|
|
195
|
-
|
|
196
|
-
```bash
|
|
197
|
-
git add src/tools/transactionTools.ts
|
|
198
|
-
git commit -m "fix: add cached property to large transaction response path
|
|
199
|
-
|
|
200
|
-
- Large responses (>90KB) now include cached and cache_info properties
|
|
201
|
-
- Maintains consistency with normal response path
|
|
202
|
-
- Fixes test failure in delta integration tests"
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
---
|
|
206
|
-
|
|
207
|
-
## Task 3: Verify Integration Test Now Passes
|
|
208
|
-
|
|
209
|
-
**Files:**
|
|
210
|
-
- Test: `src/tools/__tests__/accountTools.delta.integration.test.ts`
|
|
211
|
-
|
|
212
|
-
**Step 1: Run the failing integration test locally**
|
|
213
|
-
|
|
214
|
-
```bash
|
|
215
|
-
npm run test:integration -- src/tools/__tests__/accountTools.delta.integration.test.ts -t "reports delta usage for list_transactions after a change"
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
Expected: PASS (requires YNAB_ACCESS_TOKEN environment variable)
|
|
219
|
-
|
|
220
|
-
Note: If you don't have a YNAB token or want to skip, this is acceptable - the GitHub Action will verify.
|
|
221
|
-
|
|
222
|
-
**Step 2: Run type checking**
|
|
223
|
-
|
|
224
|
-
```bash
|
|
225
|
-
npm run type-check
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
Expected: No TypeScript errors
|
|
229
|
-
|
|
230
|
-
**Step 3: Run all unit tests to ensure no regressions**
|
|
231
|
-
|
|
232
|
-
```bash
|
|
233
|
-
npm run test:unit
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
Expected: All tests PASS
|
|
237
|
-
|
|
238
|
-
**Step 4: Commit verification checkpoint**
|
|
239
|
-
|
|
240
|
-
```bash
|
|
241
|
-
git add -A
|
|
242
|
-
git commit -m "test: verify integration test passes with cached property fix"
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
---
|
|
246
|
-
|
|
247
|
-
## Task 4: Update CHANGELOG and Documentation
|
|
248
|
-
|
|
249
|
-
**Files:**
|
|
250
|
-
- Modify: `CHANGELOG.md` (add entry at top of Unreleased section)
|
|
251
|
-
|
|
252
|
-
**Step 1: Add CHANGELOG entry**
|
|
253
|
-
|
|
254
|
-
Add this entry to the `## [Unreleased]` section in `CHANGELOG.md`:
|
|
255
|
-
|
|
256
|
-
```markdown
|
|
257
|
-
### Fixed
|
|
258
|
-
- Fixed missing `cached` property in large transaction list responses (>90KB)
|
|
259
|
-
- Large response path now includes `cached` and `cache_info` properties
|
|
260
|
-
- Maintains consistency with normal response path
|
|
261
|
-
- Resolves integration test failures when accounts have many transactions
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
**Step 2: Commit documentation**
|
|
265
|
-
|
|
266
|
-
```bash
|
|
267
|
-
git add CHANGELOG.md
|
|
268
|
-
git commit -m "docs: add CHANGELOG entry for cached property fix"
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
---
|
|
272
|
-
|
|
273
|
-
## Task 5: Push and Verify GitHub Action
|
|
274
|
-
|
|
275
|
-
**Files:**
|
|
276
|
-
- Remote: GitHub Actions CI
|
|
277
|
-
|
|
278
|
-
**Step 1: Push all commits to remote**
|
|
279
|
-
|
|
280
|
-
```bash
|
|
281
|
-
git push origin HEAD
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
Expected: Push successful
|
|
285
|
-
|
|
286
|
-
**Step 2: Monitor GitHub Action**
|
|
287
|
-
|
|
288
|
-
```bash
|
|
289
|
-
gh run watch
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
Expected:
|
|
293
|
-
- Job `unit-tests` should PASS
|
|
294
|
-
- Job `integration-core` should PASS (was previously failing at accountTools.delta.integration.test.ts)
|
|
295
|
-
|
|
296
|
-
**Step 3: Verify specific test that was failing**
|
|
297
|
-
|
|
298
|
-
Check GitHub Action logs for:
|
|
299
|
-
```
|
|
300
|
-
✓ src/tools/__tests__/accountTools.delta.integration.test.ts > Delta-backed account tool handlers > reports delta usage for list_transactions after a change
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
Expected: Green checkmark, no assertion errors
|
|
304
|
-
|
|
305
|
-
**Step 4: Create completion summary**
|
|
306
|
-
|
|
307
|
-
Document verification results:
|
|
308
|
-
```markdown
|
|
309
|
-
## Verification Complete
|
|
310
|
-
|
|
311
|
-
- ✅ Unit tests passing locally
|
|
312
|
-
- ✅ Integration tests passing locally (if run)
|
|
313
|
-
- ✅ Type checking passing
|
|
314
|
-
- ✅ GitHub Actions CI passing
|
|
315
|
-
- ✅ Specific failing test now passes
|
|
316
|
-
|
|
317
|
-
The `cached` property is now consistently included in all transaction list responses.
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
---
|
|
321
|
-
|
|
322
|
-
## Testing Strategy
|
|
323
|
-
|
|
324
|
-
**Unit Tests:**
|
|
325
|
-
- New test verifies large response path includes `cached` property
|
|
326
|
-
- Existing tests verify normal response path unchanged
|
|
327
|
-
|
|
328
|
-
**Integration Tests:**
|
|
329
|
-
- `accountTools.delta.integration.test.ts` verifies delta fetcher integration
|
|
330
|
-
- Test creates real transaction, expects `cached: false` on first call
|
|
331
|
-
- Was failing because large accounts returned `cached: undefined`
|
|
332
|
-
|
|
333
|
-
**Manual Verification:**
|
|
334
|
-
- GitHub Action will run full integration suite with real YNAB API
|
|
335
|
-
- Throttled test runner prevents rate limit issues
|
|
336
|
-
- Sequential execution ensures reliable results
|
|
337
|
-
|
|
338
|
-
---
|
|
339
|
-
|
|
340
|
-
## Rate Limiting Context (For Reference)
|
|
341
|
-
|
|
342
|
-
**Note:** The GitHub Action failure was NOT a rate limiting issue. The codebase already has excellent rate limiting:
|
|
343
|
-
|
|
344
|
-
**Existing Rate Limit Infrastructure:**
|
|
345
|
-
- `scripts/run-throttled-integration-tests.js` - Sequential test execution with request tracking
|
|
346
|
-
- Client-side throttling (200 req/hour with 20 req buffer)
|
|
347
|
-
- Request history pruning (60-minute sliding window)
|
|
348
|
-
- Intelligent wait logic with min/max bounds
|
|
349
|
-
- Per-test estimated API call counts
|
|
350
|
-
|
|
351
|
-
**No changes needed to rate limiting.** The issue was purely a missing property in the response object.
|
|
352
|
-
|
|
353
|
-
---
|
|
354
|
-
|
|
355
|
-
## Success Criteria
|
|
356
|
-
|
|
357
|
-
- ✅ Unit test passes for large response cached property
|
|
358
|
-
- ✅ Integration test `accountTools.delta.integration.test.ts:94` passes
|
|
359
|
-
- ✅ GitHub Action CI pipeline passes completely
|
|
360
|
-
- ✅ No TypeScript errors
|
|
361
|
-
- ✅ CHANGELOG updated
|
|
362
|
-
- ✅ All commits follow conventional commit format
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
# Reconciliation Error Handling Implementation Plan
|
|
2
|
-
|
|
3
|
-
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
4
|
-
|
|
5
|
-
**Goal:** Fix reconciliation integration failures by properly surfacing YNAB API errors (invalid accounts, rate limits) so tests skip or fail appropriately instead of silently returning zero creations.
|
|
6
|
-
|
|
7
|
-
**Architecture:** Add a small error-normalization layer inside the reconciliation executor to interpret YNAB SDK error payloads, propagate fatal conditions (429/invalid account) as errors, and include actionable reasons in action logs for rate-limit detection. Keep bulk/sequential creation flow intact while improving error transparency.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** TypeScript, Vitest, YNAB SDK, Node 22+
|
|
10
|
-
|
|
11
|
-
### Task 1: Normalize YNAB API errors
|
|
12
|
-
|
|
13
|
-
**Files:**
|
|
14
|
-
- Modify: `src/tools/reconciliation/executor.ts`
|
|
15
|
-
- Test: `src/tools/reconciliation/__tests__/executor.test.ts`
|
|
16
|
-
|
|
17
|
-
**Step 1: Add error normalization utilities**
|
|
18
|
-
|
|
19
|
-
```ts
|
|
20
|
-
// executor.ts (near helper section)
|
|
21
|
-
interface NormalizedYnabError { status?: number; name?: string; message: string; detail?: string }
|
|
22
|
-
function normalizeYnabError(err: unknown): NormalizedYnabError { /* parse err.error.id/detail/status, strings, Error */ }
|
|
23
|
-
function shouldPropagateYnabError(err: NormalizedYnabError): boolean { return [401, 403, 404, 429, 500].includes(err.status ?? 0); }
|
|
24
|
-
function attachStatus(err: NormalizedYnabError): Error { const e = new Error(err.message || err.detail || 'YNAB API error'); if (err.status) (e as any).status = err.status; if (err.name) e.name = err.name; return e; }
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
**Step 2: Use normalized errors in bulk chunk handling**
|
|
28
|
-
|
|
29
|
-
```ts
|
|
30
|
-
// executor.ts processBulkChunk catch
|
|
31
|
-
const ynabErr = normalizeYnabError(error);
|
|
32
|
-
if (shouldPropagateYnabError(ynabErr)) throw attachStatus(ynabErr);
|
|
33
|
-
const reason = ynabErr.message;
|
|
34
|
-
bulkOperationDetails.bulk_chunk_failures += 1;
|
|
35
|
-
actions_taken.push({ type: 'bulk_create_fallback', reason: `Bulk chunk #${chunkIndex} failed (${reason})...` });
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Expected: rate-limit or invalid-account errors now bubble; other bulk failures still fall back.
|
|
39
|
-
|
|
40
|
-
### Task 2: Propagate fatal errors during sequential creation
|
|
41
|
-
|
|
42
|
-
**Files:**
|
|
43
|
-
- Modify: `src/tools/reconciliation/executor.ts`
|
|
44
|
-
- Test: `src/tools/reconciliation/__tests__/executor.integration.test.ts`
|
|
45
|
-
|
|
46
|
-
**Step 1: Update sequential catch block**
|
|
47
|
-
|
|
48
|
-
```ts
|
|
49
|
-
const ynabErr = normalizeYnabError(error);
|
|
50
|
-
const failureReason = ynabErr.message;
|
|
51
|
-
actions_taken.push({ type: 'create_transaction_failed', reason: ...failureReason... });
|
|
52
|
-
if (shouldPropagateYnabError(ynabErr)) throw attachStatus(ynabErr);
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
Include status-aware message so `containsRateLimitFailure` sees 429 text.
|
|
56
|
-
|
|
57
|
-
**Step 2: Ensure transaction failure counters reflect thrown errors**
|
|
58
|
-
|
|
59
|
-
If fatal error occurs, increment `transaction_failures` before throw to preserve metrics.
|
|
60
|
-
|
|
61
|
-
### Task 3: Cover new error handling with tests
|
|
62
|
-
|
|
63
|
-
**Files:**
|
|
64
|
-
- Modify: `src/tools/reconciliation/__tests__/executor.test.ts`
|
|
65
|
-
- Modify: `src/tools/reconciliation/__tests__/executor.integration.test.ts` (if needed for assertions/fixtures)
|
|
66
|
-
|
|
67
|
-
**Step 1: Add unit tests for non-Error YNAB payload**
|
|
68
|
-
|
|
69
|
-
```ts
|
|
70
|
-
it('propagates rate-limit error objects with status codes', async () => {
|
|
71
|
-
mockCreateTransactions.rejects({ error: { id: '429', detail: 'Too many requests' } });
|
|
72
|
-
await expect(executeReconciliation(...)).rejects.toMatchObject({ status: 429 });
|
|
73
|
-
});
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
**Step 2: Add unit test for invalid account error propagation**
|
|
77
|
-
|
|
78
|
-
Mock 404 payload and expect rejection; verify action reason contains detail when not thrown.
|
|
79
|
-
|
|
80
|
-
**Step 3: Adjust integration expectation if fixtures rely on new messaging**
|
|
81
|
-
|
|
82
|
-
Ensure `containsRateLimitFailure` continues to match updated reason text (no code changes anticipated).
|
|
83
|
-
|
|
84
|
-
### Task 4: Verify fixes locally
|
|
85
|
-
|
|
86
|
-
**Commands:**
|
|
87
|
-
- `npx vitest run --project unit --runInBand src/tools/reconciliation/__tests__/executor.test.ts`
|
|
88
|
-
- `npm run test:integration:core -- --testNamePattern="Reconciliation Executor - Bulk Create Integration"` (rerun the failing suite)
|
|
89
|
-
|
|
90
|
-
Expected: unit tests pass; integration suite either passes or rate-limit skips instead of failing counts.
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
# YNAB MCP v0.14 Hardening Implementation Plan
|
|
2
|
-
|
|
3
|
-
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
4
|
-
|
|
5
|
-
**Goal:** Ship v0.14 with tighter schema fidelity, cache/knowledge resets, resilient config+token handling, clearer reconciliation errors, and strongly-typed dry-run payloads.
|
|
6
|
-
|
|
7
|
-
**Architecture:** Focused, TDD-driven changes inside existing server/tool layers: enforce ToolRegistry metadata/schema parity, route cache clears through DeltaCache, inject per-instance config with robust token validation, add error normalization in reconciliation executor, and replace untyped dry-run request blobs with explicit Zod schemas mirrored by handlers.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** TypeScript 5, Node 18+, MCP SDK, Zod, Vitest (unit/integration/e2e), Prettier/ESLint, docs in `docs/reference`.
|
|
10
|
-
|
|
11
|
-
### Task 1: Enforce tool metadata schema parity
|
|
12
|
-
|
|
13
|
-
**Files:**
|
|
14
|
-
- Modify: `src/server/toolRegistry.ts`
|
|
15
|
-
- Modify: `src/server/__tests__/toolRegistry.test.ts`
|
|
16
|
-
|
|
17
|
-
**Step 1: Write failing unit test**
|
|
18
|
-
Add a case that registers a tool whose `metadata.inputJsonSchema` differs from the generated schema and expects an error: `metadata input schema must match generated schema for tool "budget-sync"`.
|
|
19
|
-
|
|
20
|
-
**Step 2: Run test to see it fail**
|
|
21
|
-
`npm run test:unit -- --runInBand src/server/__tests__/toolRegistry.test.ts --testNamePattern "metadata input schema"`
|
|
22
|
-
|
|
23
|
-
**Step 3: Implement enforcement**
|
|
24
|
-
In `register`, call a new helper (e.g., `ensureMetadataSchemaMatches`) that generates the JSON schema from `inputSchema`; if `metadata.inputJsonSchema` exists and differs, throw; otherwise populate it. Remove redundant schema regeneration in `listTools` when metadata is present.
|
|
25
|
-
|
|
26
|
-
**Step 4: Re-run unit test**
|
|
27
|
-
`npm run test:unit -- --runInBand src/server/__tests__/toolRegistry.test.ts --testNamePattern "metadata input schema"`
|
|
28
|
-
|
|
29
|
-
**Step 5: Commit**
|
|
30
|
-
`git add src/server/toolRegistry.ts src/server/__tests__/toolRegistry.test.ts && git commit -m "fix: validate tool metadata schemas at registration"`
|
|
31
|
-
|
|
32
|
-
### Task 2: Make clear_cache reset delta knowledge
|
|
33
|
-
|
|
34
|
-
**Files:**
|
|
35
|
-
- Modify: `src/server/YNABMCPServer.ts`
|
|
36
|
-
- Modify: `src/server/__tests__/YNABMCPServer.integration.test.ts`
|
|
37
|
-
- Modify: `docs/reference/TOOLS.md`
|
|
38
|
-
|
|
39
|
-
**Step 1: Add failing integration test**
|
|
40
|
-
In `YNABMCPServer.integration.test.ts`, assert that after `list_accounts` populates caches, `clear_cache` drives knowledge entries to zero via `diagnostic_info` with `include_delta: true`.
|
|
41
|
-
|
|
42
|
-
**Step 2: Run test to confirm failure**
|
|
43
|
-
`npm run test:integration:domain -- --testNamePattern "clear cache runs"`
|
|
44
|
-
|
|
45
|
-
**Step 3: Implement reset**
|
|
46
|
-
In `setupToolRegistry`, change the `clear_cache` handler to call `this.deltaCache.forceFullRefresh()` (not just `cacheManager.clear()`), ensuring both cache and `ServerKnowledgeStore` reset.
|
|
47
|
-
|
|
48
|
-
**Step 4: Update docs**
|
|
49
|
-
Document in `docs/reference/TOOLS.md` that `clear_cache` now clears cache *and* delta knowledge.
|
|
50
|
-
|
|
51
|
-
**Step 5: Re-run integration slice**
|
|
52
|
-
`npm run test:integration:domain -- --testNamePattern "clear cache runs"`
|
|
53
|
-
|
|
54
|
-
**Step 6: Commit**
|
|
55
|
-
`git add src/server/YNABMCPServer.ts src/server/__tests__/YNABMCPServer.integration.test.ts docs/reference/TOOLS.md && git commit -m "feat: reset delta knowledge when cache is cleared"`
|
|
56
|
-
|
|
57
|
-
### Task 3: Reloadable config, per-instance server config, and resilient token validation
|
|
58
|
-
|
|
59
|
-
**Files:**
|
|
60
|
-
- Modify: `src/server/config.ts`
|
|
61
|
-
- Modify: `src/server/YNABMCPServer.ts`
|
|
62
|
-
- Modify: `src/server/__tests__/config.test.ts`
|
|
63
|
-
- Modify: `src/server/__tests__/YNABMCPServer.test.ts`
|
|
64
|
-
- Modify: `src/server/__tests__/server-startup.integration.test.ts`
|
|
65
|
-
- Modify: `scripts/run-throttled-integration-tests.js`
|
|
66
|
-
|
|
67
|
-
**Step 1: Verify/extend config reload tests**
|
|
68
|
-
Ensure `config.test.ts` covers re-parsing on successive `loadConfig()` calls and explicit env overrides. Add a case asserting per-call env changes are observed.
|
|
69
|
-
|
|
70
|
-
**Step 2: Add failing per-instance server test**
|
|
71
|
-
In `YNABMCPServer.test.ts`, instantiate two servers after mutating `process.env.YNAB_ACCESS_TOKEN` and assert each uses its instantiation-time config (via diagnostic/info accessor).
|
|
72
|
-
|
|
73
|
-
**Step 3: Make config injectable per instance**
|
|
74
|
-
In `YNABMCPServer.ts`, replace module-level `config` usage with `this.serverConfig = loadConfig()` inside the constructor; route YNAB API creation and tool setup through `this.serverConfig`.
|
|
75
|
-
|
|
76
|
-
**Step 4: Harden token validation**
|
|
77
|
-
Wrap `validateToken` to catch `SyntaxError` / malformed JSON or HTML responses from YNAB and throw `AuthenticationError` with guidance; keep 401/403 handling; rethrow others.
|
|
78
|
-
|
|
79
|
-
**Step 5: Windows-safe throttled runner**
|
|
80
|
-
In `scripts/run-throttled-integration-tests.js`, spawn Vitest via a platform-safe path (use `.cmd` on win32, otherwise the binary) and avoid EINVAL issues.
|
|
81
|
-
|
|
82
|
-
**Step 6: Run focused tests**
|
|
83
|
-
`npm run test:unit -- src/server/__tests__/config.test.ts src/server/__tests__/YNABMCPServer.test.ts`
|
|
84
|
-
`npm run test:integration:core -- --testNamePattern "server-startup"`
|
|
85
|
-
`node scripts/run-throttled-integration-tests.js --help` (manual sanity on Windows)
|
|
86
|
-
|
|
87
|
-
**Step 7: Commit**
|
|
88
|
-
`git add src/server/config.ts src/server/YNABMCPServer.ts src/server/__tests__/*.ts scripts/run-throttled-integration-tests.js && git commit -m "feat: reloadable config and robust token validation"`
|
|
89
|
-
|
|
90
|
-
### Task 4: Propagate fatal YNAB errors during reconciliation
|
|
91
|
-
|
|
92
|
-
**Files:**
|
|
93
|
-
- Modify: `src/tools/reconciliation/executor.ts`
|
|
94
|
-
- Modify: `src/tools/reconciliation/__tests__/executor.test.ts`
|
|
95
|
-
- Modify: `src/tools/reconciliation/__tests__/executor.integration.test.ts`
|
|
96
|
-
|
|
97
|
-
**Step 1: Add failing unit tests for error normalization**
|
|
98
|
-
Cover `normalizeYnabError`, `shouldPropagateYnabError`, and status/message shaping for 429/404 plus generic errors.
|
|
99
|
-
|
|
100
|
-
**Step 2: Implement normalization helpers**
|
|
101
|
-
Add helpers in `executor.ts` to parse YNAB SDK error objects, standard Errors, and strings; decide propagation for 401/403/404/429/500/503; attach status to thrown Error.
|
|
102
|
-
|
|
103
|
-
**Step 3: Add failing integration test for bulk rate-limit**
|
|
104
|
-
Simulate bulk create rejecting with `id: '429'` and assert `executeReconciliation` rejects with status 429 instead of silent fallback.
|
|
105
|
-
|
|
106
|
-
**Step 4: Wire helpers into bulk + sequential paths**
|
|
107
|
-
In bulk chunk catch blocks, propagate fatal errors, otherwise log and fall back; in sequential creation, log failure reasons with status and propagate fatal errors after logging.
|
|
108
|
-
|
|
109
|
-
**Step 5: Run reconciliation suites**
|
|
110
|
-
`npm run test:unit -- src/tools/reconciliation/__tests__/executor.test.ts`
|
|
111
|
-
`npm run test:integration:reconciliation` (or project pattern)
|
|
112
|
-
|
|
113
|
-
**Step 6: Commit**
|
|
114
|
-
`git add src/tools/reconciliation/executor.ts src/tools/reconciliation/__tests__/executor*.test.ts && git commit -m "fix: propagate fatal YNAB errors during reconciliation"`
|
|
115
|
-
|
|
116
|
-
### Task 5: Strongly type dry-run transaction outputs
|
|
117
|
-
|
|
118
|
-
**Files:**
|
|
119
|
-
- Modify: `src/tools/schemas/outputs/transactionMutationOutputs.ts`
|
|
120
|
-
- Modify: `src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts`
|
|
121
|
-
- Modify: `src/tools/transactionTools.ts`
|
|
122
|
-
- Modify: `src/tools/__tests__/transactionTools.test.ts`
|
|
123
|
-
- (Optional) Modify: `src/tools/__tests__/transactionTools.integration.test.ts`, `src/__tests__/workflows.e2e.test.ts`
|
|
124
|
-
|
|
125
|
-
**Step 1: Add failing schema tests**
|
|
126
|
-
Assert dry-run `request` for create/update/delete matches explicit schemas (no `budget_id`/`dry_run`, required ids present) and rejects arbitrary `z.record` payloads.
|
|
127
|
-
|
|
128
|
-
**Step 2: Define typed dry-run request schemas**
|
|
129
|
-
In `transactionMutationOutputs.ts`, introduce `CreateTransactionDryRunRequestSchema`, `UpdateTransactionDryRunRequestSchema`, and `DeleteTransactionDryRunRequestSchema` (omit `budget_id`/`dry_run`), export inferred types, and replace existing `z.record` uses in dry-run branches.
|
|
130
|
-
|
|
131
|
-
**Step 3: Update handler dry-run branches**
|
|
132
|
-
In `transactionTools.ts`, build `request` objects that include only allowed fields (exclude `budget_id`/`dry_run`) for create/update/delete dry-runs.
|
|
133
|
-
|
|
134
|
-
**Step 4: Update unit tests**
|
|
135
|
-
Adjust/create tests in `transactionTools.test.ts` to assert dry-run outputs match the new schemas and make no API calls.
|
|
136
|
-
|
|
137
|
-
**Step 5: (Optional) Integration/E2E checks**
|
|
138
|
-
Add integration/E2E assertions that dry-run outputs validate against updated schemas.
|
|
139
|
-
|
|
140
|
-
**Step 6: Run targeted suites**
|
|
141
|
-
`npm run test:unit -- src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts src/tools/__tests__/transactionTools.test.ts`
|
|
142
|
-
`npm run test:integration -- --testPathPattern=transactionTools` (if present)
|
|
143
|
-
|
|
144
|
-
**Step 7: Commit**
|
|
145
|
-
`git add src/tools/schemas/outputs/transactionMutationOutputs.ts src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts src/tools/transactionTools.ts src/tools/__tests__/transactionTools.test.ts && git commit -m "feat: type-safe dry-run transaction outputs"`
|
|
146
|
-
|
|
147
|
-
### Final verification (after all tasks)
|
|
148
|
-
|
|
149
|
-
- `npm run lint`
|
|
150
|
-
- `npm run type-check`
|
|
151
|
-
- `npm test`
|
|
152
|
-
- `npm run build` (or `npm run build:prod` if cutting release)
|
|
153
|
-
- Update `CHANGELOG.md` and `.pr-description.md` with changes and test commands.
|