@dizzlkheinz/ynab-mcpb 0.18.4 → 0.19.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/CLAUDE.md +87 -8
- package/bin/ynab-mcp-server.cjs +2 -2
- package/bin/ynab-mcp-server.js +3 -3
- package/biome.json +39 -0
- package/dist/bundle/index.cjs +67 -67
- package/dist/index.d.ts +1 -1
- package/dist/index.js +27 -27
- package/dist/server/YNABMCPServer.d.ts +3 -4
- package/dist/server/YNABMCPServer.js +111 -116
- package/dist/server/budgetResolver.d.ts +6 -5
- package/dist/server/budgetResolver.js +46 -36
- package/dist/server/cacheKeys.js +6 -6
- package/dist/server/cacheManager.js +14 -11
- package/dist/server/completions.d.ts +2 -2
- package/dist/server/completions.js +20 -15
- package/dist/server/config.d.ts +10 -5
- package/dist/server/config.js +24 -7
- package/dist/server/deltaCache.d.ts +2 -2
- package/dist/server/deltaCache.js +22 -16
- package/dist/server/deltaCache.merge.d.ts +2 -2
- package/dist/server/diagnostics.d.ts +4 -4
- package/dist/server/diagnostics.js +38 -32
- package/dist/server/errorHandler.d.ts +5 -12
- package/dist/server/errorHandler.js +219 -217
- package/dist/server/prompts.d.ts +2 -2
- package/dist/server/prompts.js +45 -45
- package/dist/server/rateLimiter.js +4 -4
- package/dist/server/requestLogger.d.ts +1 -1
- package/dist/server/requestLogger.js +40 -35
- package/dist/server/resources.d.ts +3 -3
- package/dist/server/resources.js +55 -52
- package/dist/server/responseFormatter.js +6 -6
- package/dist/server/securityMiddleware.d.ts +2 -2
- package/dist/server/securityMiddleware.js +22 -20
- package/dist/server/serverKnowledgeStore.js +1 -1
- package/dist/server/toolRegistry.d.ts +3 -3
- package/dist/server/toolRegistry.js +47 -40
- package/dist/tools/__tests__/deltaTestUtils.d.ts +3 -3
- package/dist/tools/__tests__/deltaTestUtils.js +2 -2
- package/dist/tools/accountTools.d.ts +9 -8
- package/dist/tools/accountTools.js +47 -47
- package/dist/tools/adapters.d.ts +13 -8
- package/dist/tools/adapters.js +21 -11
- package/dist/tools/budgetTools.d.ts +8 -7
- package/dist/tools/budgetTools.js +22 -22
- package/dist/tools/categoryTools.d.ts +9 -8
- package/dist/tools/categoryTools.js +68 -59
- package/dist/tools/compareTransactions/formatter.d.ts +3 -3
- package/dist/tools/compareTransactions/formatter.js +9 -9
- package/dist/tools/compareTransactions/index.d.ts +6 -6
- package/dist/tools/compareTransactions/index.js +58 -43
- package/dist/tools/compareTransactions/matcher.d.ts +1 -1
- package/dist/tools/compareTransactions/matcher.js +28 -15
- package/dist/tools/compareTransactions/parser.d.ts +2 -2
- package/dist/tools/compareTransactions/parser.js +144 -138
- package/dist/tools/compareTransactions/types.d.ts +4 -4
- package/dist/tools/compareTransactions.d.ts +1 -1
- package/dist/tools/compareTransactions.js +1 -1
- package/dist/tools/deltaFetcher.d.ts +2 -2
- package/dist/tools/deltaFetcher.js +16 -15
- package/dist/tools/deltaSupport.d.ts +4 -4
- package/dist/tools/deltaSupport.js +35 -41
- package/dist/tools/exportTransactions.d.ts +5 -4
- package/dist/tools/exportTransactions.js +61 -59
- package/dist/tools/monthTools.d.ts +7 -6
- package/dist/tools/monthTools.js +31 -29
- package/dist/tools/payeeTools.d.ts +7 -6
- package/dist/tools/payeeTools.js +28 -28
- package/dist/tools/reconcileAdapter.d.ts +2 -2
- package/dist/tools/reconcileAdapter.js +19 -12
- package/dist/tools/reconciliation/analyzer.d.ts +4 -4
- package/dist/tools/reconciliation/analyzer.js +73 -59
- package/dist/tools/reconciliation/csvParser.d.ts +3 -3
- package/dist/tools/reconciliation/csvParser.js +128 -104
- package/dist/tools/reconciliation/executor.d.ts +4 -4
- package/dist/tools/reconciliation/executor.js +148 -109
- package/dist/tools/reconciliation/index.d.ts +10 -10
- package/dist/tools/reconciliation/index.js +96 -83
- package/dist/tools/reconciliation/matcher.d.ts +3 -3
- package/dist/tools/reconciliation/matcher.js +17 -16
- package/dist/tools/reconciliation/payeeNormalizer.js +19 -8
- package/dist/tools/reconciliation/recommendationEngine.d.ts +1 -1
- package/dist/tools/reconciliation/recommendationEngine.js +40 -40
- package/dist/tools/reconciliation/reportFormatter.d.ts +2 -2
- package/dist/tools/reconciliation/reportFormatter.js +59 -58
- package/dist/tools/reconciliation/signDetector.d.ts +1 -1
- package/dist/tools/reconciliation/types.d.ts +16 -16
- package/dist/tools/reconciliation/ynabAdapter.d.ts +2 -2
- package/dist/tools/schemas/common.d.ts +1 -1
- package/dist/tools/schemas/common.js +1 -1
- package/dist/tools/schemas/outputs/accountOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/accountOutputs.js +24 -18
- package/dist/tools/schemas/outputs/budgetOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/budgetOutputs.js +14 -11
- package/dist/tools/schemas/outputs/categoryOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/categoryOutputs.js +49 -29
- package/dist/tools/schemas/outputs/comparisonOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/comparisonOutputs.js +12 -12
- package/dist/tools/schemas/outputs/index.d.ts +14 -14
- package/dist/tools/schemas/outputs/index.js +14 -14
- package/dist/tools/schemas/outputs/monthOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/monthOutputs.js +56 -41
- package/dist/tools/schemas/outputs/payeeOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/payeeOutputs.js +10 -10
- package/dist/tools/schemas/outputs/reconciliationOutputs.d.ts +2 -2
- package/dist/tools/schemas/outputs/reconciliationOutputs.js +45 -45
- package/dist/tools/schemas/outputs/transactionMutationOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/transactionMutationOutputs.js +28 -22
- package/dist/tools/schemas/outputs/transactionOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/transactionOutputs.js +43 -35
- package/dist/tools/schemas/outputs/utilityOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/utilityOutputs.js +5 -3
- package/dist/tools/schemas/shared/commonOutputs.d.ts +1 -1
- package/dist/tools/schemas/shared/commonOutputs.js +15 -9
- package/dist/tools/transactionReadTools.d.ts +11 -0
- package/dist/tools/transactionReadTools.js +202 -0
- package/dist/tools/transactionSchemas.d.ts +7 -7
- package/dist/tools/transactionSchemas.js +77 -57
- package/dist/tools/transactionTools.d.ts +6 -24
- package/dist/tools/transactionTools.js +7 -1499
- package/dist/tools/transactionUtils.d.ts +6 -6
- package/dist/tools/transactionUtils.js +78 -63
- package/dist/tools/transactionWriteTools.d.ts +20 -0
- package/dist/tools/transactionWriteTools.js +1342 -0
- package/dist/tools/utilityTools.d.ts +5 -4
- package/dist/tools/utilityTools.js +11 -11
- package/dist/types/index.d.ts +7 -7
- package/dist/types/index.js +6 -6
- package/dist/types/reconciliation.d.ts +1 -1
- package/dist/types/toolRegistration.d.ts +14 -12
- package/dist/utils/amountUtils.js +1 -1
- package/dist/utils/dateUtils.js +4 -4
- package/dist/utils/errors.d.ts +3 -3
- package/dist/utils/errors.js +4 -4
- package/dist/utils/money.d.ts +2 -2
- package/dist/utils/money.js +8 -8
- package/dist/utils/validationError.d.ts +1 -1
- package/dist/utils/validationError.js +1 -1
- package/docs/assets/examples/reconciliation-with-recommendations.json +66 -66
- package/docs/assets/schemas/reconciliation-v2.json +360 -336
- package/esbuild.config.mjs +53 -50
- package/meta.json +12548 -12548
- package/package.json +98 -111
- package/scripts/analyze-bundle.mjs +33 -30
- package/scripts/create-pr-description.js +169 -120
- package/scripts/run-all-tests.js +178 -169
- package/scripts/run-domain-integration-tests.js +28 -18
- package/scripts/run-generate-mcpb.js +19 -17
- package/scripts/run-throttled-integration-tests.js +92 -83
- package/scripts/test-delta-params.mjs +149 -120
- package/scripts/test-recommendations.ts +36 -32
- package/scripts/tmpTransaction.ts +80 -43
- package/scripts/validate-env.js +98 -91
- package/scripts/verify-build.js +78 -76
- package/src/__tests__/comprehensive.integration.test.ts +1281 -1154
- package/src/__tests__/performance.test.ts +723 -671
- package/src/__tests__/setup.ts +442 -395
- package/src/__tests__/smoke.e2e.test.ts +41 -39
- package/src/__tests__/testRunner.ts +314 -295
- package/src/__tests__/testUtils.ts +456 -364
- package/src/__tests__/tools/reconciliation/csvParser.integration.test.ts +109 -107
- package/src/__tests__/tools/reconciliation/real-world.integration.test.ts +41 -41
- package/src/index.ts +68 -59
- package/src/server/CLAUDE.md +480 -0
- package/src/server/YNABMCPServer.ts +821 -794
- package/src/server/__tests__/YNABMCPServer.integration.test.ts +929 -893
- package/src/server/__tests__/YNABMCPServer.test.ts +903 -899
- package/src/server/__tests__/budgetResolver.test.ts +466 -423
- package/src/server/__tests__/cacheManager.test.ts +891 -874
- package/src/server/__tests__/completions.integration.test.ts +115 -106
- package/src/server/__tests__/completions.test.ts +334 -313
- package/src/server/__tests__/config.test.ts +98 -86
- package/src/server/__tests__/deltaCache.merge.test.ts +774 -703
- package/src/server/__tests__/deltaCache.swr.test.ts +198 -153
- package/src/server/__tests__/deltaCache.test.ts +946 -759
- package/src/server/__tests__/diagnostics.test.ts +825 -792
- package/src/server/__tests__/errorHandler.integration.test.ts +512 -462
- package/src/server/__tests__/errorHandler.test.ts +402 -397
- package/src/server/__tests__/prompts.test.ts +424 -347
- package/src/server/__tests__/rateLimiter.test.ts +313 -309
- package/src/server/__tests__/requestLogger.test.ts +443 -403
- package/src/server/__tests__/resources.template.test.ts +196 -185
- package/src/server/__tests__/resources.test.ts +294 -288
- package/src/server/__tests__/security.integration.test.ts +487 -421
- package/src/server/__tests__/securityMiddleware.test.ts +519 -444
- package/src/server/__tests__/server-startup.integration.test.ts +509 -490
- package/src/server/__tests__/serverKnowledgeStore.test.ts +174 -173
- package/src/server/__tests__/toolRegistration.test.ts +239 -210
- package/src/server/__tests__/toolRegistry.test.ts +907 -845
- package/src/server/budgetResolver.ts +221 -181
- package/src/server/cacheKeys.ts +6 -6
- package/src/server/cacheManager.ts +498 -484
- package/src/server/completions.ts +267 -243
- package/src/server/config.ts +35 -14
- package/src/server/deltaCache.merge.ts +146 -128
- package/src/server/deltaCache.ts +352 -309
- package/src/server/diagnostics.ts +257 -242
- package/src/server/errorHandler.ts +747 -744
- package/src/server/prompts.ts +181 -176
- package/src/server/rateLimiter.ts +131 -129
- package/src/server/requestLogger.ts +350 -322
- package/src/server/resources.ts +442 -374
- package/src/server/responseFormatter.ts +41 -37
- package/src/server/securityMiddleware.ts +223 -205
- package/src/server/serverKnowledgeStore.ts +67 -67
- package/src/server/toolRegistry.ts +508 -474
- package/src/tools/CLAUDE.md +604 -0
- package/src/tools/__tests__/accountTools.delta.integration.test.ts +128 -111
- package/src/tools/__tests__/accountTools.integration.test.ts +129 -111
- package/src/tools/__tests__/accountTools.test.ts +685 -638
- package/src/tools/__tests__/adapters.test.ts +142 -108
- package/src/tools/__tests__/budgetTools.delta.integration.test.ts +73 -73
- package/src/tools/__tests__/budgetTools.integration.test.ts +132 -124
- package/src/tools/__tests__/budgetTools.test.ts +442 -413
- package/src/tools/__tests__/categoryTools.delta.integration.test.ts +76 -68
- package/src/tools/__tests__/categoryTools.integration.test.ts +314 -288
- package/src/tools/__tests__/categoryTools.test.ts +656 -625
- package/src/tools/__tests__/compareTransactions/formatter.test.ts +535 -462
- package/src/tools/__tests__/compareTransactions/index.test.ts +378 -358
- package/src/tools/__tests__/compareTransactions/matcher.test.ts +497 -398
- package/src/tools/__tests__/compareTransactions/parser.test.ts +765 -747
- package/src/tools/__tests__/compareTransactions.test.ts +352 -332
- package/src/tools/__tests__/compareTransactions.window.test.ts +150 -146
- package/src/tools/__tests__/deltaFetcher.scheduled.integration.test.ts +69 -65
- package/src/tools/__tests__/deltaFetcher.test.ts +325 -265
- package/src/tools/__tests__/deltaSupport.test.ts +211 -184
- package/src/tools/__tests__/deltaTestUtils.ts +37 -33
- package/src/tools/__tests__/exportTransactions.test.ts +205 -200
- package/src/tools/__tests__/monthTools.delta.integration.test.ts +68 -68
- package/src/tools/__tests__/monthTools.integration.test.ts +178 -166
- package/src/tools/__tests__/monthTools.test.ts +561 -512
- package/src/tools/__tests__/payeeTools.delta.integration.test.ts +68 -68
- package/src/tools/__tests__/payeeTools.integration.test.ts +158 -142
- package/src/tools/__tests__/payeeTools.test.ts +486 -434
- package/src/tools/__tests__/transactionSchemas.test.ts +1202 -1186
- package/src/tools/__tests__/transactionTools.integration.test.ts +875 -825
- package/src/tools/__tests__/transactionTools.test.ts +4923 -4366
- package/src/tools/__tests__/transactionUtils.test.ts +1004 -977
- package/src/tools/__tests__/utilityTools.integration.test.ts +32 -32
- package/src/tools/__tests__/utilityTools.test.ts +68 -58
- package/src/tools/accountTools.ts +293 -271
- package/src/tools/adapters.ts +120 -63
- package/src/tools/budgetTools.ts +121 -116
- package/src/tools/categoryTools.ts +379 -339
- package/src/tools/compareTransactions/formatter.ts +131 -119
- package/src/tools/compareTransactions/index.ts +249 -214
- package/src/tools/compareTransactions/matcher.ts +259 -209
- package/src/tools/compareTransactions/parser.ts +517 -487
- package/src/tools/compareTransactions/types.ts +38 -38
- package/src/tools/compareTransactions.ts +1 -1
- package/src/tools/deltaFetcher.ts +281 -260
- package/src/tools/deltaSupport.ts +264 -259
- package/src/tools/exportTransactions.ts +230 -218
- package/src/tools/monthTools.ts +180 -165
- package/src/tools/payeeTools.ts +152 -140
- package/src/tools/reconcileAdapter.ts +297 -252
- package/src/tools/reconciliation/CLAUDE.md +506 -0
- package/src/tools/reconciliation/__tests__/adapter.causes.test.ts +133 -124
- package/src/tools/reconciliation/__tests__/adapter.test.ts +249 -230
- package/src/tools/reconciliation/__tests__/analyzer.test.ts +408 -400
- package/src/tools/reconciliation/__tests__/csvParser.test.ts +71 -69
- package/src/tools/reconciliation/__tests__/executor.integration.test.ts +348 -323
- package/src/tools/reconciliation/__tests__/executor.progress.test.ts +503 -457
- package/src/tools/reconciliation/__tests__/executor.test.ts +898 -831
- package/src/tools/reconciliation/__tests__/matcher.test.ts +667 -663
- package/src/tools/reconciliation/__tests__/payeeNormalizer.test.ts +296 -276
- package/src/tools/reconciliation/__tests__/recommendationEngine.integration.test.ts +692 -624
- package/src/tools/reconciliation/__tests__/recommendationEngine.test.ts +1008 -989
- package/src/tools/reconciliation/__tests__/reconciliation.delta.integration.test.ts +187 -146
- package/src/tools/reconciliation/__tests__/reportFormatter.test.ts +583 -533
- package/src/tools/reconciliation/__tests__/scenarios/adapterCurrency.scenario.test.ts +75 -74
- package/src/tools/reconciliation/__tests__/scenarios/extremes.scenario.test.ts +70 -62
- package/src/tools/reconciliation/__tests__/scenarios/repeatAmount.scenario.test.ts +102 -88
- package/src/tools/reconciliation/__tests__/schemaUrl.test.ts +56 -55
- package/src/tools/reconciliation/__tests__/signDetector.test.ts +209 -206
- package/src/tools/reconciliation/__tests__/ynabAdapter.test.ts +66 -60
- package/src/tools/reconciliation/analyzer.ts +564 -504
- package/src/tools/reconciliation/csvParser.ts +656 -609
- package/src/tools/reconciliation/executor.ts +1290 -1128
- package/src/tools/reconciliation/index.ts +580 -528
- package/src/tools/reconciliation/matcher.ts +256 -240
- package/src/tools/reconciliation/payeeNormalizer.ts +92 -78
- package/src/tools/reconciliation/recommendationEngine.ts +357 -345
- package/src/tools/reconciliation/reportFormatter.ts +343 -307
- package/src/tools/reconciliation/signDetector.ts +89 -83
- package/src/tools/reconciliation/types.ts +164 -159
- package/src/tools/reconciliation/ynabAdapter.ts +17 -15
- package/src/tools/schemas/CLAUDE.md +546 -0
- package/src/tools/schemas/common.ts +1 -1
- package/src/tools/schemas/outputs/__tests__/accountOutputs.test.ts +410 -409
- package/src/tools/schemas/outputs/__tests__/budgetOutputs.test.ts +305 -299
- package/src/tools/schemas/outputs/__tests__/categoryOutputs.test.ts +431 -430
- package/src/tools/schemas/outputs/__tests__/comparisonOutputs.test.ts +510 -495
- package/src/tools/schemas/outputs/__tests__/dateValidation.test.ts +179 -153
- package/src/tools/schemas/outputs/__tests__/discrepancyDirection.test.ts +293 -254
- package/src/tools/schemas/outputs/__tests__/monthOutputs.test.ts +457 -457
- package/src/tools/schemas/outputs/__tests__/payeeOutputs.test.ts +362 -356
- package/src/tools/schemas/outputs/__tests__/reconciliationOutputs.test.ts +402 -399
- package/src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts +225 -211
- package/src/tools/schemas/outputs/__tests__/transactionOutputs.test.ts +457 -454
- package/src/tools/schemas/outputs/__tests__/utilityOutputs.test.ts +316 -315
- package/src/tools/schemas/outputs/accountOutputs.ts +40 -34
- package/src/tools/schemas/outputs/budgetOutputs.ts +24 -19
- package/src/tools/schemas/outputs/categoryOutputs.ts +76 -56
- package/src/tools/schemas/outputs/comparisonOutputs.ts +192 -169
- package/src/tools/schemas/outputs/index.ts +163 -163
- package/src/tools/schemas/outputs/monthOutputs.ts +95 -80
- package/src/tools/schemas/outputs/payeeOutputs.ts +18 -18
- package/src/tools/schemas/outputs/reconciliationOutputs.ts +386 -373
- package/src/tools/schemas/outputs/transactionMutationOutputs.ts +259 -231
- package/src/tools/schemas/outputs/transactionOutputs.ts +81 -71
- package/src/tools/schemas/outputs/utilityOutputs.ts +90 -84
- package/src/tools/schemas/shared/commonOutputs.ts +27 -19
- package/src/tools/toolCategories.ts +114 -114
- package/src/tools/transactionReadTools.ts +327 -0
- package/src/tools/transactionSchemas.ts +322 -291
- package/src/tools/transactionTools.ts +84 -2246
- package/src/tools/transactionUtils.ts +507 -422
- package/src/tools/transactionWriteTools.ts +2110 -0
- package/src/tools/utilityTools.ts +46 -41
- package/src/types/CLAUDE.md +477 -0
- package/src/types/__tests__/index.test.ts +51 -51
- package/src/types/index.ts +43 -39
- package/src/types/integration-tests.d.ts +26 -26
- package/src/types/reconciliation.ts +29 -29
- package/src/types/toolAnnotations.ts +30 -30
- package/src/types/toolRegistration.ts +43 -32
- package/src/utils/CLAUDE.md +508 -0
- package/src/utils/__tests__/dateUtils.test.ts +174 -168
- package/src/utils/__tests__/money.test.ts +193 -187
- package/src/utils/amountUtils.ts +5 -5
- package/src/utils/baseError.ts +5 -5
- package/src/utils/dateUtils.ts +29 -26
- package/src/utils/errors.ts +14 -14
- package/src/utils/money.ts +66 -52
- package/src/utils/validationError.ts +1 -1
- package/tsconfig.json +29 -29
- package/tsconfig.prod.json +16 -16
- package/vitest-reporters/split-json-reporter.ts +247 -204
- package/vitest.config.ts +99 -95
- package/.prettierignore +0 -10
- package/.prettierrc.json +0 -10
- package/eslint.config.js +0 -49
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
* }
|
|
45
45
|
*/
|
|
46
46
|
|
|
47
|
-
import { z } from
|
|
47
|
+
import { z } from "zod";
|
|
48
48
|
|
|
49
49
|
// ============================================================================
|
|
50
50
|
// NESTED SCHEMAS FOR COMPOSITION
|
|
@@ -57,10 +57,10 @@ import { z } from 'zod';
|
|
|
57
57
|
* @see src/utils/money.ts - MoneyValue type definition
|
|
58
58
|
*/
|
|
59
59
|
export const MoneyValueSchema = z.object({
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
amount: z.number().finite(),
|
|
61
|
+
currency: z.string(),
|
|
62
|
+
formatted: z.string(),
|
|
63
|
+
memo: z.string().optional(),
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
export type MoneyValue = z.infer<typeof MoneyValueSchema>;
|
|
@@ -82,27 +82,28 @@ export type MoneyValue = z.infer<typeof MoneyValueSchema>;
|
|
|
82
82
|
* ```
|
|
83
83
|
*/
|
|
84
84
|
export const IsoDateWithCalendarValidationSchema = z
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
85
|
+
.string()
|
|
86
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in ISO format (YYYY-MM-DD)")
|
|
87
|
+
.refine(
|
|
88
|
+
(dateStr) => {
|
|
89
|
+
const parsed = Date.parse(dateStr);
|
|
90
|
+
if (Number.isNaN(parsed)) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
// Verify that the parsed date components match the original string
|
|
94
|
+
// This catches cases like "2025-02-31" which Date.parse might coerce to "2025-03-03"
|
|
95
|
+
const date = new Date(parsed);
|
|
96
|
+
const year = date.getUTCFullYear();
|
|
97
|
+
const month = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
98
|
+
const day = String(date.getUTCDate()).padStart(2, "0");
|
|
99
|
+
const reconstructed = `${year}-${month}-${day}`;
|
|
100
|
+
return reconstructed === dateStr;
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
message:
|
|
104
|
+
"Invalid calendar date (e.g., month must be 01-12, day must be valid for the month)",
|
|
105
|
+
},
|
|
106
|
+
);
|
|
106
107
|
|
|
107
108
|
/**
|
|
108
109
|
* Bank transaction from CSV import (output format with money formatting).
|
|
@@ -117,13 +118,13 @@ export const IsoDateWithCalendarValidationSchema = z
|
|
|
117
118
|
* @see src/tools/reconcileAdapter.ts:77-80 - toBankTransactionView function
|
|
118
119
|
*/
|
|
119
120
|
export const BankTransactionSchema = z.object({
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
121
|
+
id: z.string().uuid(),
|
|
122
|
+
date: IsoDateWithCalendarValidationSchema,
|
|
123
|
+
amount: z.number(),
|
|
124
|
+
payee: z.string(),
|
|
125
|
+
memo: z.string().optional(),
|
|
126
|
+
original_csv_row: z.number(),
|
|
127
|
+
amount_money: MoneyValueSchema, // Added by adapter
|
|
127
128
|
});
|
|
128
129
|
|
|
129
130
|
export type BankTransaction = z.infer<typeof BankTransactionSchema>;
|
|
@@ -141,15 +142,15 @@ export type BankTransaction = z.infer<typeof BankTransactionSchema>;
|
|
|
141
142
|
* @see src/tools/reconcileAdapter.ts:82-85 - toYNABTransactionView function
|
|
142
143
|
*/
|
|
143
144
|
export const YNABTransactionSimpleSchema = z.object({
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
145
|
+
id: z.string(),
|
|
146
|
+
date: IsoDateWithCalendarValidationSchema,
|
|
147
|
+
amount: z.number(),
|
|
148
|
+
payee_name: z.string().nullable(),
|
|
149
|
+
category_name: z.string().nullable(),
|
|
150
|
+
cleared: z.enum(["cleared", "uncleared", "reconciled"]),
|
|
151
|
+
approved: z.boolean(),
|
|
152
|
+
memo: z.string().nullable().optional(),
|
|
153
|
+
amount_money: MoneyValueSchema, // Added by adapter
|
|
153
154
|
});
|
|
154
155
|
|
|
155
156
|
export type YNABTransactionSimple = z.infer<typeof YNABTransactionSimpleSchema>;
|
|
@@ -161,10 +162,10 @@ export type YNABTransactionSimple = z.infer<typeof YNABTransactionSimpleSchema>;
|
|
|
161
162
|
* @see src/tools/reconciliation/types.ts - MatchCandidate interface
|
|
162
163
|
*/
|
|
163
164
|
export const MatchCandidateSchema = z.object({
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
ynab_transaction: YNABTransactionSimpleSchema,
|
|
166
|
+
confidence: z.number().min(0).max(100),
|
|
167
|
+
match_reason: z.string(),
|
|
168
|
+
explanation: z.string(),
|
|
168
169
|
});
|
|
169
170
|
|
|
170
171
|
export type MatchCandidate = z.infer<typeof MatchCandidateSchema>;
|
|
@@ -196,11 +197,13 @@ export type MatchCandidate = z.infer<typeof MatchCandidateSchema>;
|
|
|
196
197
|
* };
|
|
197
198
|
* ```
|
|
198
199
|
*/
|
|
199
|
-
export function deriveConfidenceFromScore(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
200
|
+
export function deriveConfidenceFromScore(
|
|
201
|
+
score: number,
|
|
202
|
+
): "high" | "medium" | "low" | "none" {
|
|
203
|
+
if (score >= 90) return "high";
|
|
204
|
+
if (score >= 60) return "medium";
|
|
205
|
+
if (score >= 1) return "low";
|
|
206
|
+
return "none";
|
|
204
207
|
}
|
|
205
208
|
|
|
206
209
|
/**
|
|
@@ -222,27 +225,30 @@ export function deriveConfidenceFromScore(score: number): 'high' | 'medium' | 'l
|
|
|
222
225
|
* - 'none': confidence_score === 0
|
|
223
226
|
*/
|
|
224
227
|
export const TransactionMatchSchema = z
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
228
|
+
.object({
|
|
229
|
+
bank_transaction: BankTransactionSchema,
|
|
230
|
+
ynab_transaction: YNABTransactionSimpleSchema.optional(),
|
|
231
|
+
candidates: z.array(MatchCandidateSchema).optional(),
|
|
232
|
+
confidence: z.enum(["high", "medium", "low", "none"]),
|
|
233
|
+
confidence_score: z.number().min(0).max(100),
|
|
234
|
+
match_reason: z.string(),
|
|
235
|
+
top_confidence: z.number().optional(),
|
|
236
|
+
action_hint: z.string().optional(),
|
|
237
|
+
recommendation: z.string().optional(),
|
|
238
|
+
})
|
|
239
|
+
.refine(
|
|
240
|
+
(data) => {
|
|
241
|
+
const expectedConfidence = deriveConfidenceFromScore(
|
|
242
|
+
data.confidence_score,
|
|
243
|
+
);
|
|
244
|
+
return data.confidence === expectedConfidence;
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
message:
|
|
248
|
+
"Confidence mismatch: confidence enum does not match confidence_score",
|
|
249
|
+
path: ["confidence"],
|
|
250
|
+
},
|
|
251
|
+
);
|
|
246
252
|
|
|
247
253
|
export type TransactionMatch = z.infer<typeof TransactionMatchSchema>;
|
|
248
254
|
|
|
@@ -253,12 +259,12 @@ export type TransactionMatch = z.infer<typeof TransactionMatchSchema>;
|
|
|
253
259
|
* @see src/tools/reconciliation/types.ts - BalanceInfo interface
|
|
254
260
|
*/
|
|
255
261
|
export const BalanceInfoSchema = z.object({
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
+
current_cleared: MoneyValueSchema,
|
|
263
|
+
current_uncleared: MoneyValueSchema,
|
|
264
|
+
current_total: MoneyValueSchema,
|
|
265
|
+
target_statement: MoneyValueSchema,
|
|
266
|
+
discrepancy: MoneyValueSchema,
|
|
267
|
+
on_track: z.boolean(),
|
|
262
268
|
});
|
|
263
269
|
|
|
264
270
|
export type BalanceInfo = z.infer<typeof BalanceInfoSchema>;
|
|
@@ -270,17 +276,17 @@ export type BalanceInfo = z.infer<typeof BalanceInfoSchema>;
|
|
|
270
276
|
* @see src/tools/reconciliation/types.ts - ReconciliationSummary interface
|
|
271
277
|
*/
|
|
272
278
|
export const ReconciliationSummarySchema = z.object({
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
279
|
+
statement_date_range: z.string(),
|
|
280
|
+
bank_transactions_count: z.number(),
|
|
281
|
+
ynab_transactions_count: z.number(),
|
|
282
|
+
auto_matched: z.number(),
|
|
283
|
+
suggested_matches: z.number(),
|
|
284
|
+
unmatched_bank: z.number(),
|
|
285
|
+
unmatched_ynab: z.number(),
|
|
286
|
+
current_cleared_balance: MoneyValueSchema,
|
|
287
|
+
target_statement_balance: MoneyValueSchema,
|
|
288
|
+
discrepancy: MoneyValueSchema,
|
|
289
|
+
discrepancy_explanation: z.string(),
|
|
284
290
|
});
|
|
285
291
|
|
|
286
292
|
export type ReconciliationSummary = z.infer<typeof ReconciliationSummarySchema>;
|
|
@@ -292,12 +298,12 @@ export type ReconciliationSummary = z.infer<typeof ReconciliationSummarySchema>;
|
|
|
292
298
|
* @see src/tools/reconciliation/types.ts - ReconciliationInsight interface
|
|
293
299
|
*/
|
|
294
300
|
export const ReconciliationInsightSchema = z.object({
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
+
id: z.string(),
|
|
302
|
+
type: z.enum(["repeat_amount", "near_match", "anomaly"]),
|
|
303
|
+
severity: z.enum(["info", "warning", "critical"]),
|
|
304
|
+
title: z.string(),
|
|
305
|
+
description: z.string(),
|
|
306
|
+
evidence: z.record(z.string(), z.unknown()).optional(),
|
|
301
307
|
});
|
|
302
308
|
|
|
303
309
|
export type ReconciliationInsight = z.infer<typeof ReconciliationInsightSchema>;
|
|
@@ -308,85 +314,90 @@ export type ReconciliationInsight = z.infer<typeof ReconciliationInsightSchema>;
|
|
|
308
314
|
*
|
|
309
315
|
* @see src/tools/reconciliation/types.ts - ActionableRecommendation union type
|
|
310
316
|
*/
|
|
311
|
-
export const ActionableRecommendationSchema = z.discriminatedUnion(
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
317
|
+
export const ActionableRecommendationSchema = z.discriminatedUnion(
|
|
318
|
+
"action_type",
|
|
319
|
+
[
|
|
320
|
+
// Create transaction recommendation
|
|
321
|
+
z.object({
|
|
322
|
+
id: z.string(),
|
|
323
|
+
action_type: z.literal("create_transaction"),
|
|
324
|
+
priority: z.enum(["high", "medium", "low"]),
|
|
325
|
+
confidence: z.number().min(0).max(1),
|
|
326
|
+
message: z.string(),
|
|
327
|
+
reason: z.string(),
|
|
328
|
+
estimated_impact: MoneyValueSchema,
|
|
329
|
+
account_id: z.string(),
|
|
330
|
+
source_insight_id: z.string().optional(),
|
|
331
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
332
|
+
parameters: z.object({
|
|
333
|
+
account_id: z.string(),
|
|
334
|
+
date: IsoDateWithCalendarValidationSchema,
|
|
335
|
+
amount: z.number(),
|
|
336
|
+
payee_name: z.string(),
|
|
337
|
+
memo: z.string().optional(),
|
|
338
|
+
cleared: z.enum(["cleared", "uncleared"]),
|
|
339
|
+
approved: z.boolean(),
|
|
340
|
+
category_id: z.string().optional(),
|
|
341
|
+
}),
|
|
342
|
+
}),
|
|
343
|
+
// Update cleared status recommendation
|
|
344
|
+
z.object({
|
|
345
|
+
id: z.string(),
|
|
346
|
+
action_type: z.literal("update_cleared"),
|
|
347
|
+
priority: z.enum(["high", "medium", "low"]),
|
|
348
|
+
confidence: z.number().min(0).max(1),
|
|
349
|
+
message: z.string(),
|
|
350
|
+
reason: z.string(),
|
|
351
|
+
estimated_impact: MoneyValueSchema,
|
|
352
|
+
account_id: z.string(),
|
|
353
|
+
source_insight_id: z.string().optional(),
|
|
354
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
355
|
+
parameters: z.object({
|
|
356
|
+
transaction_id: z.string(),
|
|
357
|
+
cleared: z.enum(["cleared", "uncleared", "reconciled"]),
|
|
358
|
+
}),
|
|
359
|
+
}),
|
|
360
|
+
// Review duplicate recommendation
|
|
361
|
+
z.object({
|
|
362
|
+
id: z.string(),
|
|
363
|
+
action_type: z.literal("review_duplicate"),
|
|
364
|
+
priority: z.enum(["high", "medium", "low"]),
|
|
365
|
+
confidence: z.number().min(0).max(1),
|
|
366
|
+
message: z.string(),
|
|
367
|
+
reason: z.string(),
|
|
368
|
+
estimated_impact: MoneyValueSchema,
|
|
369
|
+
account_id: z.string(),
|
|
370
|
+
source_insight_id: z.string().optional(),
|
|
371
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
372
|
+
parameters: z.object({
|
|
373
|
+
candidate_ids: z.array(z.string()),
|
|
374
|
+
bank_transaction: BankTransactionSchema,
|
|
375
|
+
suggested_match_id: z.string().optional(),
|
|
376
|
+
}),
|
|
377
|
+
}),
|
|
378
|
+
// Manual review recommendation
|
|
379
|
+
z.object({
|
|
380
|
+
id: z.string(),
|
|
381
|
+
action_type: z.literal("manual_review"),
|
|
382
|
+
priority: z.enum(["high", "medium", "low"]),
|
|
383
|
+
confidence: z.number().min(0).max(1),
|
|
384
|
+
message: z.string(),
|
|
385
|
+
reason: z.string(),
|
|
386
|
+
estimated_impact: MoneyValueSchema,
|
|
387
|
+
account_id: z.string(),
|
|
388
|
+
source_insight_id: z.string().optional(),
|
|
389
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
390
|
+
parameters: z.object({
|
|
391
|
+
issue_type: z.string(),
|
|
392
|
+
related_transactions: z.array(z.string()),
|
|
393
|
+
}),
|
|
394
|
+
}),
|
|
395
|
+
],
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
export type ActionableRecommendation = z.infer<
|
|
399
|
+
typeof ActionableRecommendationSchema
|
|
400
|
+
>;
|
|
390
401
|
|
|
391
402
|
/**
|
|
392
403
|
* Account balance snapshot with money formatting.
|
|
@@ -395,9 +406,9 @@ export type ActionableRecommendation = z.infer<typeof ActionableRecommendationSc
|
|
|
395
406
|
* @see src/tools/reconcileAdapter.ts:138-142 - convertAccountSnapshot function
|
|
396
407
|
*/
|
|
397
408
|
export const AccountSnapshotSchema = z.object({
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
409
|
+
balance: MoneyValueSchema,
|
|
410
|
+
cleared_balance: MoneyValueSchema,
|
|
411
|
+
uncleared_balance: MoneyValueSchema,
|
|
401
412
|
});
|
|
402
413
|
|
|
403
414
|
export type AccountSnapshot = z.infer<typeof AccountSnapshotSchema>;
|
|
@@ -412,32 +423,32 @@ export type AccountSnapshot = z.infer<typeof AccountSnapshotSchema>;
|
|
|
412
423
|
* Used when a transaction is successfully created.
|
|
413
424
|
*/
|
|
414
425
|
export const CreatedTransactionSchema = z
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
426
|
+
.object({
|
|
427
|
+
id: z.string(),
|
|
428
|
+
date: z.string(),
|
|
429
|
+
amount: z.number(),
|
|
430
|
+
memo: z.string().nullable().optional(),
|
|
431
|
+
cleared: z.enum(["cleared", "uncleared", "reconciled"]).optional(),
|
|
432
|
+
approved: z.boolean().optional(),
|
|
433
|
+
payee_name: z.string().nullable().optional(),
|
|
434
|
+
category_name: z.string().nullable().optional(),
|
|
435
|
+
import_id: z.string().nullable().optional(),
|
|
436
|
+
})
|
|
437
|
+
.passthrough(); // Allow additional YNAB API fields
|
|
427
438
|
|
|
428
439
|
/**
|
|
429
440
|
* Transaction creation payload.
|
|
430
441
|
* Used when documenting what would be created (dry run) or what failed to create.
|
|
431
442
|
*/
|
|
432
443
|
export const TransactionCreationPayloadSchema = z.object({
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
444
|
+
account_id: z.string(),
|
|
445
|
+
date: z.string(),
|
|
446
|
+
amount: z.number(),
|
|
447
|
+
payee_name: z.string().optional(),
|
|
448
|
+
memo: z.string().optional(),
|
|
449
|
+
cleared: z.enum(["cleared", "uncleared"]).optional(),
|
|
450
|
+
approved: z.boolean().optional(),
|
|
451
|
+
import_id: z.string().optional(),
|
|
441
452
|
});
|
|
442
453
|
|
|
443
454
|
/**
|
|
@@ -445,9 +456,9 @@ export const TransactionCreationPayloadSchema = z.object({
|
|
|
445
456
|
* Used when documenting status or date changes.
|
|
446
457
|
*/
|
|
447
458
|
export const TransactionUpdatePayloadSchema = z.object({
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
459
|
+
transaction_id: z.string(),
|
|
460
|
+
new_date: z.string().optional(),
|
|
461
|
+
cleared: z.enum(["cleared", "uncleared", "reconciled"]).optional(),
|
|
451
462
|
});
|
|
452
463
|
|
|
453
464
|
/**
|
|
@@ -455,8 +466,8 @@ export const TransactionUpdatePayloadSchema = z.object({
|
|
|
455
466
|
* Used when a transaction creation is skipped due to duplicate detection.
|
|
456
467
|
*/
|
|
457
468
|
export const DuplicateDetectionPayloadSchema = z.object({
|
|
458
|
-
|
|
459
|
-
|
|
469
|
+
transaction_id: z.string().nullable(),
|
|
470
|
+
import_id: z.string().optional(),
|
|
460
471
|
});
|
|
461
472
|
|
|
462
473
|
/**
|
|
@@ -473,54 +484,54 @@ export const DuplicateDetectionPayloadSchema = z.object({
|
|
|
473
484
|
* @see src/tools/reconciliation/executor.ts:472-480 - update_transaction action (dry run)
|
|
474
485
|
* @see src/tools/reconciliation/executor.ts:515-520 - update_transaction action (real)
|
|
475
486
|
*/
|
|
476
|
-
export const ExecutionActionRecordSchema = z.discriminatedUnion(
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
487
|
+
export const ExecutionActionRecordSchema = z.discriminatedUnion("type", [
|
|
488
|
+
// Successful transaction creation
|
|
489
|
+
z.object({
|
|
490
|
+
type: z.literal("create_transaction"),
|
|
491
|
+
transaction: CreatedTransactionSchema.nullable(),
|
|
492
|
+
reason: z.string(),
|
|
493
|
+
bulk_chunk_index: z.number().optional(),
|
|
494
|
+
correlation_key: z.string().optional(),
|
|
495
|
+
}),
|
|
496
|
+
// Failed transaction creation
|
|
497
|
+
z.object({
|
|
498
|
+
type: z.literal("create_transaction_failed"),
|
|
499
|
+
transaction: TransactionCreationPayloadSchema,
|
|
500
|
+
reason: z.string(),
|
|
501
|
+
bulk_chunk_index: z.number().optional(),
|
|
502
|
+
correlation_key: z.string().optional(),
|
|
503
|
+
}),
|
|
504
|
+
// Duplicate transaction detected
|
|
505
|
+
z.object({
|
|
506
|
+
type: z.literal("create_transaction_duplicate"),
|
|
507
|
+
transaction: DuplicateDetectionPayloadSchema,
|
|
508
|
+
reason: z.string(),
|
|
509
|
+
bulk_chunk_index: z.number(),
|
|
510
|
+
correlation_key: z.string().optional(),
|
|
511
|
+
duplicate: z.literal(true),
|
|
512
|
+
}),
|
|
513
|
+
// Transaction update (status/date change)
|
|
514
|
+
z.object({
|
|
515
|
+
type: z.literal("update_transaction"),
|
|
516
|
+
transaction: z.union([
|
|
517
|
+
CreatedTransactionSchema.nullable(), // Real execution
|
|
518
|
+
TransactionUpdatePayloadSchema, // Dry run
|
|
519
|
+
]),
|
|
520
|
+
reason: z.string(),
|
|
521
|
+
}),
|
|
522
|
+
// Balance alignment checkpoint
|
|
523
|
+
z.object({
|
|
524
|
+
type: z.literal("balance_checkpoint"),
|
|
525
|
+
transaction: z.null(),
|
|
526
|
+
reason: z.string(),
|
|
527
|
+
}),
|
|
528
|
+
// Bulk create fallback to sequential
|
|
529
|
+
z.object({
|
|
530
|
+
type: z.literal("bulk_create_fallback"),
|
|
531
|
+
transaction: z.null(),
|
|
532
|
+
reason: z.string(),
|
|
533
|
+
bulk_chunk_index: z.number(),
|
|
534
|
+
}),
|
|
524
535
|
]);
|
|
525
536
|
|
|
526
537
|
export type ExecutionActionRecord = z.infer<typeof ExecutionActionRecordSchema>;
|
|
@@ -532,15 +543,15 @@ export type ExecutionActionRecord = z.infer<typeof ExecutionActionRecordSchema>;
|
|
|
532
543
|
* @see src/tools/reconciliation/executor.ts:38-48 - ExecutionSummary interface
|
|
533
544
|
*/
|
|
534
545
|
export const ExecutionSummarySchema = z.object({
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
546
|
+
bank_transactions_count: z.number(),
|
|
547
|
+
ynab_transactions_count: z.number(),
|
|
548
|
+
matches_found: z.number(),
|
|
549
|
+
missing_in_ynab: z.number(),
|
|
550
|
+
missing_in_bank: z.number(),
|
|
551
|
+
transactions_created: z.number(),
|
|
552
|
+
transactions_updated: z.number(),
|
|
553
|
+
dates_adjusted: z.number(),
|
|
554
|
+
dry_run: z.boolean(),
|
|
544
555
|
});
|
|
545
556
|
|
|
546
557
|
export type ExecutionSummary = z.infer<typeof ExecutionSummarySchema>;
|
|
@@ -558,19 +569,19 @@ export type ExecutionSummary = z.infer<typeof ExecutionSummarySchema>;
|
|
|
558
569
|
* @see src/tools/reconciliation/executor.ts:50-68 - BulkOperationDetails interface
|
|
559
570
|
*/
|
|
560
571
|
export const BulkOperationDetailsSchema = z
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
572
|
+
.object({
|
|
573
|
+
chunks_processed: z.number(),
|
|
574
|
+
bulk_successes: z.number(),
|
|
575
|
+
sequential_fallbacks: z.number(),
|
|
576
|
+
duplicates_detected: z.number(),
|
|
577
|
+
failed_transactions: z.number(),
|
|
578
|
+
bulk_chunk_failures: z.number(),
|
|
579
|
+
transaction_failures: z.number(),
|
|
580
|
+
sequential_attempts: z.number().optional(),
|
|
581
|
+
})
|
|
582
|
+
.refine((data) => data.failed_transactions === data.transaction_failures, {
|
|
583
|
+
message: "failed_transactions must equal transaction_failures",
|
|
584
|
+
});
|
|
574
585
|
|
|
575
586
|
export type BulkOperationDetails = z.infer<typeof BulkOperationDetailsSchema>;
|
|
576
587
|
|
|
@@ -588,15 +599,15 @@ export type BulkOperationDetails = z.infer<typeof BulkOperationDetailsSchema>;
|
|
|
588
599
|
* @see src/tools/reconciliation/executor.ts:69-79 - ExecutionResult interface
|
|
589
600
|
*/
|
|
590
601
|
export const ExecutionResultSchema = z.object({
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
602
|
+
summary: ExecutionSummarySchema,
|
|
603
|
+
account_balance: z.object({
|
|
604
|
+
before: AccountSnapshotSchema,
|
|
605
|
+
after: AccountSnapshotSchema,
|
|
606
|
+
}),
|
|
607
|
+
actions_taken: z.array(ExecutionActionRecordSchema),
|
|
608
|
+
recommendations: z.array(z.string()),
|
|
609
|
+
balance_reconciliation: z.unknown().optional(),
|
|
610
|
+
bulk_operation_details: BulkOperationDetailsSchema.optional(),
|
|
600
611
|
});
|
|
601
612
|
|
|
602
613
|
export type ExecutionResult = z.infer<typeof ExecutionResultSchema>;
|
|
@@ -614,20 +625,20 @@ export type ExecutionResult = z.infer<typeof ExecutionResultSchema>;
|
|
|
614
625
|
* @see src/tools/reconcileAdapter.ts:19-25 - AdapterOptions interface with extensible auditMetadata
|
|
615
626
|
*/
|
|
616
627
|
export const AuditMetadataSchema = z
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
628
|
+
.object({
|
|
629
|
+
data_freshness: z.string(),
|
|
630
|
+
data_source: z.string(),
|
|
631
|
+
server_knowledge: z.number().optional(),
|
|
632
|
+
fetched_at: z.string(),
|
|
633
|
+
accounts_count: z.number().optional(),
|
|
634
|
+
transactions_count: z.number().optional(),
|
|
635
|
+
cache_status: z.object({
|
|
636
|
+
accounts_cached: z.boolean(),
|
|
637
|
+
transactions_cached: z.boolean(),
|
|
638
|
+
delta_merge_applied: z.boolean(),
|
|
639
|
+
}),
|
|
640
|
+
})
|
|
641
|
+
.catchall(z.unknown());
|
|
631
642
|
|
|
632
643
|
export type AuditMetadata = z.infer<typeof AuditMetadataSchema>;
|
|
633
644
|
|
|
@@ -707,90 +718,92 @@ export type AuditMetadata = z.infer<typeof AuditMetadataSchema>;
|
|
|
707
718
|
* @see src/tools/reconciliation/index.ts:364-402 - mapCsvFormatForPayload function
|
|
708
719
|
*/
|
|
709
720
|
export const CsvFormatMetadataSchema = z.object({
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
721
|
+
delimiter: z.string(),
|
|
722
|
+
decimal_separator: z.string(),
|
|
723
|
+
thousands_separator: z.string().nullable(),
|
|
724
|
+
date_format: z.string(),
|
|
725
|
+
header_row: z.boolean(),
|
|
726
|
+
date_column: z.string().nullable(),
|
|
727
|
+
amount_column: z.string().nullable(),
|
|
728
|
+
payee_column: z.string().nullable(),
|
|
718
729
|
});
|
|
719
730
|
|
|
720
731
|
export type CsvFormatMetadata = z.infer<typeof CsvFormatMetadataSchema>;
|
|
721
732
|
|
|
722
733
|
// Define the structured data schema without refinement first
|
|
723
734
|
const StructuredReconciliationDataBaseSchema = z.object({
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
735
|
+
version: z.string(),
|
|
736
|
+
schema_url: z.string(),
|
|
737
|
+
generated_at: z.string(),
|
|
738
|
+
account: z.object({
|
|
739
|
+
id: z.string().optional(),
|
|
740
|
+
name: z.string().optional(),
|
|
741
|
+
}),
|
|
742
|
+
summary: ReconciliationSummarySchema,
|
|
743
|
+
balance: BalanceInfoSchema.extend({
|
|
744
|
+
discrepancy_direction: z.enum(["balanced", "ynab_higher", "bank_higher"]),
|
|
745
|
+
}),
|
|
746
|
+
insights: z.array(ReconciliationInsightSchema),
|
|
747
|
+
next_steps: z.array(z.string()),
|
|
748
|
+
matches: z.object({
|
|
749
|
+
auto: z.array(TransactionMatchSchema),
|
|
750
|
+
suggested: z.array(TransactionMatchSchema),
|
|
751
|
+
}),
|
|
752
|
+
unmatched: z.object({
|
|
753
|
+
bank: z.array(BankTransactionSchema),
|
|
754
|
+
ynab: z.array(YNABTransactionSimpleSchema),
|
|
755
|
+
}),
|
|
756
|
+
recommendations: z.array(ActionableRecommendationSchema).optional(),
|
|
757
|
+
csv_format: CsvFormatMetadataSchema.optional(),
|
|
758
|
+
execution: ExecutionResultSchema.optional(),
|
|
759
|
+
audit: AuditMetadataSchema.optional(),
|
|
749
760
|
});
|
|
750
761
|
|
|
751
762
|
export const ReconcileAccountOutputSchema = z
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
export type ReconcileAccountOutput = z.infer<
|
|
763
|
+
.union([
|
|
764
|
+
// Human + structured data (when include_structured_data=true) - check this FIRST
|
|
765
|
+
z.object({
|
|
766
|
+
human: z.string(),
|
|
767
|
+
structured: StructuredReconciliationDataBaseSchema,
|
|
768
|
+
}),
|
|
769
|
+
// Human narrative only (default mode) - check this SECOND
|
|
770
|
+
z.object({
|
|
771
|
+
human: z.string(),
|
|
772
|
+
}),
|
|
773
|
+
])
|
|
774
|
+
.refine(
|
|
775
|
+
(data) => {
|
|
776
|
+
// Only validate if this is the structured variant (has 'structured' property)
|
|
777
|
+
if ("structured" in data && data.structured) {
|
|
778
|
+
const discrepancyAmount = data.structured.balance.discrepancy.amount;
|
|
779
|
+
const direction = data.structured.balance.discrepancy_direction;
|
|
780
|
+
|
|
781
|
+
// If absolute discrepancy < 0.01, direction must be 'balanced'
|
|
782
|
+
if (Math.abs(discrepancyAmount) < 0.01) {
|
|
783
|
+
return direction === "balanced";
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// If discrepancy > 0, direction must be 'ynab_higher'
|
|
787
|
+
if (discrepancyAmount > 0) {
|
|
788
|
+
return direction === "ynab_higher";
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// If discrepancy < 0, direction must be 'bank_higher'
|
|
792
|
+
if (discrepancyAmount < 0) {
|
|
793
|
+
return direction === "bank_higher";
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// Human-only variant always passes validation
|
|
798
|
+
return true;
|
|
799
|
+
},
|
|
800
|
+
{
|
|
801
|
+
message:
|
|
802
|
+
"Discrepancy direction mismatch: direction must match the numeric discrepancy amount",
|
|
803
|
+
path: ["balance", "discrepancy_direction"],
|
|
804
|
+
},
|
|
805
|
+
);
|
|
806
|
+
|
|
807
|
+
export type ReconcileAccountOutput = z.infer<
|
|
808
|
+
typeof ReconcileAccountOutputSchema
|
|
809
|
+
>;
|