@kansei-link/bantou 0.2.0 → 0.2.1

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.
@@ -1,117 +1,117 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$id": "https://github.com/michielinksee/kansei-link-cockpit/blob/main/data/keyword-dict-schema.json",
4
- "title": "Cockpit MCP Keyword Dictionary",
5
- "description": "Schema for Stage 1 keyword classification dictionaries used by Cockpit MCP's two-stage classifier. Each category maps a list of keywords (= service names, vendor names, common 摘要 patterns) to a 勘定科目 + 税区分.",
6
- "type": "object",
7
- "required": ["version", "locale", "tax_jurisdiction", "categories"],
8
- "properties": {
9
- "version": {
10
- "type": "string",
11
- "pattern": "^\\d+\\.\\d+\\.\\d+$",
12
- "description": "Semver version of this dictionary"
13
- },
14
- "locale": {
15
- "type": "string",
16
- "pattern": "^[a-z]{2}-[A-Z]{2}$",
17
- "description": "BCP 47 locale code (e.g., ja-JP)"
18
- },
19
- "tax_jurisdiction": {
20
- "type": "string",
21
- "pattern": "^[A-Z]{2}$",
22
- "description": "ISO 3166-1 alpha-2 country code for tax regime"
23
- },
24
- "tax_code_default": {
25
- "type": "integer",
26
- "description": "Default tax_code if no per-keyword override (= freee 税区分 ID)"
27
- },
28
- "last_updated": {
29
- "type": "string",
30
- "format": "date",
31
- "description": "ISO 8601 YYYY-MM-DD"
32
- },
33
- "maintainer": {
34
- "type": "string"
35
- },
36
- "license": {
37
- "type": "string",
38
- "default": "MIT"
39
- },
40
- "description": {
41
- "type": "string"
42
- },
43
- "notes": {
44
- "type": "array",
45
- "items": { "type": "string" },
46
- "description": "Free-form notes / caveats / algorithm details"
47
- },
48
- "categories": {
49
- "type": "array",
50
- "minItems": 1,
51
- "items": {
52
- "type": "object",
53
- "required": ["id", "name_ja", "freee_account_code", "default_tax_code", "keywords"],
54
- "properties": {
55
- "id": {
56
- "type": "string",
57
- "pattern": "^[a-z_]+$",
58
- "description": "Stable ID (lowercase, underscore-separated)"
59
- },
60
- "name_ja": {
61
- "type": "string",
62
- "description": "Japanese display name (= 勘定科目名)"
63
- },
64
- "name_en": {
65
- "type": "string",
66
- "description": "English equivalent for international expansion"
67
- },
68
- "freee_account_code": {
69
- "type": "integer",
70
- "description": "freee 勘定科目 ID (= account_item_id in freee API)"
71
- },
72
- "mf_account_code": {
73
- "type": "integer",
74
- "description": "Money Forward 勘定科目 ID (optional, set when freee + MF mapping confirmed)"
75
- },
76
- "default_tax_code": {
77
- "type": "integer",
78
- "description": "freee 税区分 ID (= tax_code, e.g., 0=対象外, 1=課税仕入8%, 2=課税仕入10%)"
79
- },
80
- "description": {
81
- "type": "string"
82
- },
83
- "amount_threshold_min": {
84
- "type": "number",
85
- "description": "Minimum amount (JPY) — below this, transaction does NOT match this category. Used for tiered rules like 会議費 (≤¥10K) vs 交際費 (>¥10K)."
86
- },
87
- "amount_threshold_max": {
88
- "type": "number",
89
- "description": "Maximum amount (JPY) — above this, transaction does NOT match this category. Used for fixed-asset thresholds like 事務用品費 (<¥100K) vs 備品 (≥¥100K)."
90
- },
91
- "amount_overflow_category": {
92
- "type": "string",
93
- "description": "If amount exceeds amount_threshold_max, auto-redirect to this category id (e.g., 会議費 → 交際費)."
94
- },
95
- "special_pattern": {
96
- "type": "string",
97
- "enum": [
98
- "salary_employee_match",
99
- "transfer_katakana_person",
100
- "transfer_professional"
101
- ],
102
- "description": "Custom matching logic that requires more than keyword substring (= e.g., '振込+カナ人名 → 外注費' requires regex + name detection)"
103
- },
104
- "keywords": {
105
- "type": "array",
106
- "minItems": 1,
107
- "items": {
108
- "type": "string",
109
- "minLength": 1
110
- },
111
- "description": "List of substrings to match against normalized 摘要 (= 全角→半角 + lowercase). Order matters for priority within the same category. Across categories, the FIRST matching category wins (= top categories take priority)."
112
- }
113
- }
114
- }
115
- }
116
- }
117
- }
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://github.com/michielinksee/kansei-link-cockpit/blob/main/data/keyword-dict-schema.json",
4
+ "title": "Cockpit MCP Keyword Dictionary",
5
+ "description": "Schema for Stage 1 keyword classification dictionaries used by Cockpit MCP's two-stage classifier. Each category maps a list of keywords (= service names, vendor names, common 摘要 patterns) to a 勘定科目 + 税区分.",
6
+ "type": "object",
7
+ "required": ["version", "locale", "tax_jurisdiction", "categories"],
8
+ "properties": {
9
+ "version": {
10
+ "type": "string",
11
+ "pattern": "^\\d+\\.\\d+\\.\\d+$",
12
+ "description": "Semver version of this dictionary"
13
+ },
14
+ "locale": {
15
+ "type": "string",
16
+ "pattern": "^[a-z]{2}-[A-Z]{2}$",
17
+ "description": "BCP 47 locale code (e.g., ja-JP)"
18
+ },
19
+ "tax_jurisdiction": {
20
+ "type": "string",
21
+ "pattern": "^[A-Z]{2}$",
22
+ "description": "ISO 3166-1 alpha-2 country code for tax regime"
23
+ },
24
+ "tax_code_default": {
25
+ "type": "integer",
26
+ "description": "Default tax_code if no per-keyword override (= freee 税区分 ID)"
27
+ },
28
+ "last_updated": {
29
+ "type": "string",
30
+ "format": "date",
31
+ "description": "ISO 8601 YYYY-MM-DD"
32
+ },
33
+ "maintainer": {
34
+ "type": "string"
35
+ },
36
+ "license": {
37
+ "type": "string",
38
+ "default": "MIT"
39
+ },
40
+ "description": {
41
+ "type": "string"
42
+ },
43
+ "notes": {
44
+ "type": "array",
45
+ "items": { "type": "string" },
46
+ "description": "Free-form notes / caveats / algorithm details"
47
+ },
48
+ "categories": {
49
+ "type": "array",
50
+ "minItems": 1,
51
+ "items": {
52
+ "type": "object",
53
+ "required": ["id", "name_ja", "freee_account_code", "default_tax_code", "keywords"],
54
+ "properties": {
55
+ "id": {
56
+ "type": "string",
57
+ "pattern": "^[a-z_]+$",
58
+ "description": "Stable ID (lowercase, underscore-separated)"
59
+ },
60
+ "name_ja": {
61
+ "type": "string",
62
+ "description": "Japanese display name (= 勘定科目名)"
63
+ },
64
+ "name_en": {
65
+ "type": "string",
66
+ "description": "English equivalent for international expansion"
67
+ },
68
+ "freee_account_code": {
69
+ "type": "integer",
70
+ "description": "freee 勘定科目 ID (= account_item_id in freee API)"
71
+ },
72
+ "mf_account_code": {
73
+ "type": "integer",
74
+ "description": "Money Forward 勘定科目 ID (optional, set when freee + MF mapping confirmed)"
75
+ },
76
+ "default_tax_code": {
77
+ "type": "integer",
78
+ "description": "freee 税区分 ID (= tax_code, e.g., 0=対象外, 1=課税仕入8%, 2=課税仕入10%)"
79
+ },
80
+ "description": {
81
+ "type": "string"
82
+ },
83
+ "amount_threshold_min": {
84
+ "type": "number",
85
+ "description": "Minimum amount (JPY) — below this, transaction does NOT match this category. Used for tiered rules like 会議費 (≤¥10K) vs 交際費 (>¥10K)."
86
+ },
87
+ "amount_threshold_max": {
88
+ "type": "number",
89
+ "description": "Maximum amount (JPY) — above this, transaction does NOT match this category. Used for fixed-asset thresholds like 事務用品費 (<¥100K) vs 備品 (≥¥100K)."
90
+ },
91
+ "amount_overflow_category": {
92
+ "type": "string",
93
+ "description": "If amount exceeds amount_threshold_max, auto-redirect to this category id (e.g., 会議費 → 交際費)."
94
+ },
95
+ "special_pattern": {
96
+ "type": "string",
97
+ "enum": [
98
+ "salary_employee_match",
99
+ "transfer_katakana_person",
100
+ "transfer_professional"
101
+ ],
102
+ "description": "Custom matching logic that requires more than keyword substring (= e.g., '振込+カナ人名 → 外注費' requires regex + name detection)"
103
+ },
104
+ "keywords": {
105
+ "type": "array",
106
+ "minItems": 1,
107
+ "items": {
108
+ "type": "string",
109
+ "minLength": 1
110
+ },
111
+ "description": "List of substrings to match against normalized 摘要 (= 全角→半角 + lowercase). Order matters for priority within the same category. Across categories, the FIRST matching category wins (= top categories take priority)."
112
+ }
113
+ }
114
+ }
115
+ }
116
+ }
117
+ }
@@ -1,170 +1,170 @@
1
- {
2
- "version": "1.1.0",
3
- "locale": "ja-JP",
4
-
5
- "overseas_saas_providers": [
6
- "aws", "amazon web services",
7
- "google cloud", "gcp",
8
- "azure", "microsoft azure",
9
- "openai", "anthropic", "claude",
10
- "cursor",
11
- "github", "gitlab",
12
- "cloudflare",
13
- "vercel", "netlify", "heroku",
14
- "digitalocean", "linode",
15
- "stripe",
16
- "figma", "adobe", "canva",
17
- "slack", "discord",
18
- "zoom",
19
- "notion", "asana", "trello", "jira",
20
- "dropbox", "datadog", "sentry",
21
- "twilio", "sendgrid", "mailgun",
22
- "hubspot", "intercom",
23
- "1password", "lastpass",
24
- "postman", "linear"
25
- ],
26
-
27
- "overseas_ad_platforms": [
28
- "google ads", "google adwords", "adwords",
29
- "meta", "facebook ads", "instagram ads",
30
- "twitter ads", "x ads",
31
- "linkedin ads",
32
- "tiktok ads",
33
- "youtube ads",
34
- "pinterest ads",
35
- "reddit ads",
36
- "apple search ads"
37
- ],
38
-
39
- "domestic_telecom_providers": [
40
- "docomo", "ドコモ",
41
- "au", "kddi",
42
- "softbank", "ソフトバンク",
43
- "ntt", "ntt東日本", "ntt西日本", "nttコミュニケーションズ",
44
- "さくらインターネット", "さくら",
45
- "ocn",
46
- "フレッツ", "flets",
47
- "biglobe", "ビッグローブ",
48
- "so-net", "ソネット",
49
- "お名前.com", "onamae",
50
- "iij", "インターネットイニシアティブ",
51
- "楽天モバイル", "rakuten mobile",
52
- "uqモバイル", "uq mobile",
53
- "ワイモバイル", "y!mobile"
54
- ],
55
-
56
- "domestic_ad_platforms": [
57
- "yahoo!広告", "yahoo広告", "yda", "ydn",
58
- "line ads", "line広告",
59
- "smartnews広告", "gunosy広告",
60
- "indeed"
61
- ],
62
-
63
- "jct_indicator_keywords": [
64
- "jct",
65
- "消費税",
66
- "インボイス",
67
- "invoice",
68
- "適格請求書"
69
- ],
70
-
71
- "asset_capitalization": {
72
- "expense_max": 99999,
73
- "lump_sum_3yr_max": 199999,
74
- "sme_immediate_max": 299999
75
- },
76
-
77
- "withholding_tax": {
78
- "bracket_1_ceiling": 1000000,
79
- "rate_bracket_1": 0.1021,
80
- "rate_bracket_2": 0.2042
81
- },
82
-
83
- "consumption_tax": {
84
- "standard_rate": 10,
85
- "reduced_rate": 8,
86
- "exempt_rate": 0,
87
-
88
- "newspaper_keywords": [
89
- "新聞", "日経", "朝日", "読売", "毎日", "産経",
90
- "newspaper", "nikkei"
91
- ],
92
-
93
- "food_beverage_keywords": [
94
- "弁当", "ケータリング", "テイクアウト", "持ち帰り",
95
- "出前", "デリバリー", "uber eats", "ubereats",
96
- "出前館", "wolt", "menu",
97
- "コンビニ", "スーパー"
98
- ],
99
-
100
- "takeout_delivery_keywords": [
101
- "テイクアウト", "持ち帰り", "出前", "デリバリー",
102
- "uber eats", "ubereats", "出前館", "wolt",
103
- "menu", "弁当", "仕出し"
104
- ],
105
-
106
- "food_purchase_keywords": [
107
- "コンビニ", "セブンイレブン", "ローソン", "ファミマ",
108
- "スーパー", "イオン", "西友", "ライフ",
109
- "成城石井", "紀ノ国屋", "オーケー",
110
- "食品", "飲料", "お茶", "コーヒー豆",
111
- "菓子", "お菓子", "スイーツ"
112
- ],
113
-
114
- "catering_with_service_keywords": [
115
- "ケータリング", "出張料理", "パーティー",
116
- "配膳", "サービス料"
117
- ],
118
-
119
- "residential_rent_keywords": [
120
- "住居", "住宅", "マンション", "アパート",
121
- "居住用", "住居用", "自宅", "社宅",
122
- "residential"
123
- ],
124
-
125
- "non_taxable_categories": [
126
- "salary",
127
- "membership_fee",
128
- "insurance",
129
- "taxes_dues",
130
- "donation",
131
- "condolence"
132
- ],
133
-
134
- "non_taxable_reasons": {
135
- "salary": "給与 — 消費税対象外",
136
- "membership_fee": "諸会費 — 原則として消費税対象外",
137
- "insurance": "保険料 — 消費税非課税(保険業法に基づく保険契約)",
138
- "taxes_dues": "租税公課 — 消費税不課税(国・地方への公的支出)",
139
- "donation": "寄付金 — 消費税不課税(対価性なし)",
140
- "condolence": "慶弔費 — 消費税不課税(対価性なし)"
141
- }
142
- },
143
-
144
- "invoice_system": {
145
- "registration_prefix": "T",
146
- "registration_digits": 13,
147
- "transitional_periods": [
148
- {
149
- "start": "2023-10-01",
150
- "end": "2026-09-30",
151
- "deduction_rate": 80,
152
- "label": "経過措置第1期 — 仕入税額控除80%"
153
- },
154
- {
155
- "start": "2026-10-01",
156
- "end": "2029-09-30",
157
- "deduction_rate": 50,
158
- "label": "経過措置第2期 — 仕入税額控除50%"
159
- },
160
- {
161
- "start": "2029-10-01",
162
- "end": "9999-12-31",
163
- "deduction_rate": 0,
164
- "label": "経過措置終了 — 仕入税額控除不可"
165
- }
166
- ],
167
- "small_business_threshold": 10000,
168
- "small_business_note": "1万円未満の課税仕入れは、少額特例により帳簿のみで仕入税額控除可(基準期間の課税売上高1億円以下の事業者、2029年9月まで)"
169
- }
170
- }
1
+ {
2
+ "version": "1.1.0",
3
+ "locale": "ja-JP",
4
+
5
+ "overseas_saas_providers": [
6
+ "aws", "amazon web services",
7
+ "google cloud", "gcp",
8
+ "azure", "microsoft azure",
9
+ "openai", "anthropic", "claude",
10
+ "cursor",
11
+ "github", "gitlab",
12
+ "cloudflare",
13
+ "vercel", "netlify", "heroku",
14
+ "digitalocean", "linode",
15
+ "stripe",
16
+ "figma", "adobe", "canva",
17
+ "slack", "discord",
18
+ "zoom",
19
+ "notion", "asana", "trello", "jira",
20
+ "dropbox", "datadog", "sentry",
21
+ "twilio", "sendgrid", "mailgun",
22
+ "hubspot", "intercom",
23
+ "1password", "lastpass",
24
+ "postman", "linear"
25
+ ],
26
+
27
+ "overseas_ad_platforms": [
28
+ "google ads", "google adwords", "adwords",
29
+ "meta", "facebook ads", "instagram ads",
30
+ "twitter ads", "x ads",
31
+ "linkedin ads",
32
+ "tiktok ads",
33
+ "youtube ads",
34
+ "pinterest ads",
35
+ "reddit ads",
36
+ "apple search ads"
37
+ ],
38
+
39
+ "domestic_telecom_providers": [
40
+ "docomo", "ドコモ",
41
+ "au", "kddi",
42
+ "softbank", "ソフトバンク",
43
+ "ntt", "ntt東日本", "ntt西日本", "nttコミュニケーションズ",
44
+ "さくらインターネット", "さくら",
45
+ "ocn",
46
+ "フレッツ", "flets",
47
+ "biglobe", "ビッグローブ",
48
+ "so-net", "ソネット",
49
+ "お名前.com", "onamae",
50
+ "iij", "インターネットイニシアティブ",
51
+ "楽天モバイル", "rakuten mobile",
52
+ "uqモバイル", "uq mobile",
53
+ "ワイモバイル", "y!mobile"
54
+ ],
55
+
56
+ "domestic_ad_platforms": [
57
+ "yahoo!広告", "yahoo広告", "yda", "ydn",
58
+ "line ads", "line広告",
59
+ "smartnews広告", "gunosy広告",
60
+ "indeed"
61
+ ],
62
+
63
+ "jct_indicator_keywords": [
64
+ "jct",
65
+ "消費税",
66
+ "インボイス",
67
+ "invoice",
68
+ "適格請求書"
69
+ ],
70
+
71
+ "asset_capitalization": {
72
+ "expense_max": 99999,
73
+ "lump_sum_3yr_max": 199999,
74
+ "sme_immediate_max": 299999
75
+ },
76
+
77
+ "withholding_tax": {
78
+ "bracket_1_ceiling": 1000000,
79
+ "rate_bracket_1": 0.1021,
80
+ "rate_bracket_2": 0.2042
81
+ },
82
+
83
+ "consumption_tax": {
84
+ "standard_rate": 10,
85
+ "reduced_rate": 8,
86
+ "exempt_rate": 0,
87
+
88
+ "newspaper_keywords": [
89
+ "新聞", "日経", "朝日", "読売", "毎日", "産経",
90
+ "newspaper", "nikkei"
91
+ ],
92
+
93
+ "food_beverage_keywords": [
94
+ "弁当", "ケータリング", "テイクアウト", "持ち帰り",
95
+ "出前", "デリバリー", "uber eats", "ubereats",
96
+ "出前館", "wolt", "menu",
97
+ "コンビニ", "スーパー"
98
+ ],
99
+
100
+ "takeout_delivery_keywords": [
101
+ "テイクアウト", "持ち帰り", "出前", "デリバリー",
102
+ "uber eats", "ubereats", "出前館", "wolt",
103
+ "menu", "弁当", "仕出し"
104
+ ],
105
+
106
+ "food_purchase_keywords": [
107
+ "コンビニ", "セブンイレブン", "ローソン", "ファミマ",
108
+ "スーパー", "イオン", "西友", "ライフ",
109
+ "成城石井", "紀ノ国屋", "オーケー",
110
+ "食品", "飲料", "お茶", "コーヒー豆",
111
+ "菓子", "お菓子", "スイーツ"
112
+ ],
113
+
114
+ "catering_with_service_keywords": [
115
+ "ケータリング", "出張料理", "パーティー",
116
+ "配膳", "サービス料"
117
+ ],
118
+
119
+ "residential_rent_keywords": [
120
+ "住居", "住宅", "マンション", "アパート",
121
+ "居住用", "住居用", "自宅", "社宅",
122
+ "residential"
123
+ ],
124
+
125
+ "non_taxable_categories": [
126
+ "salary",
127
+ "membership_fee",
128
+ "insurance",
129
+ "taxes_dues",
130
+ "donation",
131
+ "condolence"
132
+ ],
133
+
134
+ "non_taxable_reasons": {
135
+ "salary": "給与 — 消費税対象外",
136
+ "membership_fee": "諸会費 — 原則として消費税対象外",
137
+ "insurance": "保険料 — 消費税非課税(保険業法に基づく保険契約)",
138
+ "taxes_dues": "租税公課 — 消費税不課税(国・地方への公的支出)",
139
+ "donation": "寄付金 — 消費税不課税(対価性なし)",
140
+ "condolence": "慶弔費 — 消費税不課税(対価性なし)"
141
+ }
142
+ },
143
+
144
+ "invoice_system": {
145
+ "registration_prefix": "T",
146
+ "registration_digits": 13,
147
+ "transitional_periods": [
148
+ {
149
+ "start": "2023-10-01",
150
+ "end": "2026-09-30",
151
+ "deduction_rate": 80,
152
+ "label": "経過措置第1期 — 仕入税額控除80%"
153
+ },
154
+ {
155
+ "start": "2026-10-01",
156
+ "end": "2029-09-30",
157
+ "deduction_rate": 50,
158
+ "label": "経過措置第2期 — 仕入税額控除50%"
159
+ },
160
+ {
161
+ "start": "2029-10-01",
162
+ "end": "9999-12-31",
163
+ "deduction_rate": 0,
164
+ "label": "経過措置終了 — 仕入税額控除不可"
165
+ }
166
+ ],
167
+ "small_business_threshold": 10000,
168
+ "small_business_note": "1万円未満の課税仕入れは、少額特例により帳簿のみで仕入税額控除可(基準期間の課税売上高1億円以下の事業者、2029年9月まで)"
169
+ }
170
+ }
@@ -61,44 +61,44 @@ export class ClaudeClassifier {
61
61
  }
62
62
  buildSystemPrompt() {
63
63
  const categoryList = this.categories.map(c => `- ${c.id} (${c.name_ja}): ${c.description || 'no description'}`).join('\n');
64
- return `You are a Japanese tax accounting classifier. Classify business transactions into 1 of 14 categories.
65
-
66
- # Categories
67
-
68
- ${categoryList}
69
-
70
- # Output format
71
-
72
- Return JSON only. No markdown, no explanation outside JSON:
73
-
74
- {
75
- "category_id": "<one of the category ids above>",
76
- "confidence": "high|medium|low",
77
- "reasoning": "<one short sentence in Japanese, 50 chars max>"
78
- }
79
-
80
- # Confidence rules
81
-
82
- - **high**: Clear unambiguous match (e.g., "楽天モバイル ¥5,500" → communications obvious)
83
- - **medium**: Leans toward one but other plausible (e.g., 海外 SaaS amount that could be utilities OR communications)
84
- - **low**: 2+ categories equally plausible OR insufficient info
85
-
86
- # Japanese tax accounting rules
87
-
88
- - 飲食 ≤¥10,000 → meeting_meal (会議費)
89
- - 飲食 >¥10,000 → entertainment (交際費)
90
- - 海外 SaaS (Anthropic / OpenAI / GitHub / AWS / Cloudflare / etc.) → communications + tax_code 0 (国外取引)
91
- - 軽減税率 (8%): 食品 / 新聞定期購読 / 持ち帰り飲食
92
- - 標準税率 (10%): 店内飲食 / 通常物販 / 国内サービス
64
+ return `You are a Japanese tax accounting classifier. Classify business transactions into 1 of 14 categories.
65
+
66
+ # Categories
67
+
68
+ ${categoryList}
69
+
70
+ # Output format
71
+
72
+ Return JSON only. No markdown, no explanation outside JSON:
73
+
74
+ {
75
+ "category_id": "<one of the category ids above>",
76
+ "confidence": "high|medium|low",
77
+ "reasoning": "<one short sentence in Japanese, 50 chars max>"
78
+ }
79
+
80
+ # Confidence rules
81
+
82
+ - **high**: Clear unambiguous match (e.g., "楽天モバイル ¥5,500" → communications obvious)
83
+ - **medium**: Leans toward one but other plausible (e.g., 海外 SaaS amount that could be utilities OR communications)
84
+ - **low**: 2+ categories equally plausible OR insufficient info
85
+
86
+ # Japanese tax accounting rules
87
+
88
+ - 飲食 ≤¥10,000 → meeting_meal (会議費)
89
+ - 飲食 >¥10,000 → entertainment (交際費)
90
+ - 海外 SaaS (Anthropic / OpenAI / GitHub / AWS / Cloudflare / etc.) → communications + tax_code 0 (国外取引)
91
+ - 軽減税率 (8%): 食品 / 新聞定期購読 / 持ち帰り飲食
92
+ - 標準税率 (10%): 店内飲食 / 通常物販 / 国内サービス
93
93
  - 給与 / 借入 / 社保 / 投資 / ATM出金 / 公共料金 → これらは別途 exclusion check で escalate されるので、 通常分類すべきではない (= ただし keyword match で対象外な場合のみ、 確信あれば salary / loan etc. でもOK)`;
94
94
  }
95
95
  buildUserPrompt(tx) {
96
- return `Transaction:
97
- - amount: ${tx.amount} JPY
98
- - memo: ${tx.memo}
99
- - date: ${tx.date}
100
- - partner: ${tx.partner_name || '(unknown)'}
101
-
96
+ return `Transaction:
97
+ - amount: ${tx.amount} JPY
98
+ - memo: ${tx.memo}
99
+ - date: ${tx.date}
100
+ - partner: ${tx.partner_name || '(unknown)'}
101
+
102
102
  Classify into 1 category. JSON only.`;
103
103
  }
104
104
  parseResponse(text) {