hs-predict 0.5.1

HS code prediction for chemical products — Akinator-style interactive classification with rule-based and LLM hybrid engine
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
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
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
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
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
# hs-predict

[![Crates.io](https://img.shields.io/crates/v/hs-predict.svg)](https://crates.io/crates/hs-predict)
[![docs.rs](https://docs.rs/hs-predict/badge.svg)](https://docs.rs/hs-predict)
[![CI](https://github.com/kent-tokyo/hs-predict/actions/workflows/ci.yml/badge.svg)](https://github.com/kent-tokyo/hs-predict/actions)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](#ライセンス)

**化学品のHSコード(国際統一商品分類)予測ライブラリ。**

`hs-predict` は **Akinatorスタイルの段階的対話** を採用しています。分類に必要な情報だけを1問ずつ問いかけ、ルールベースエンジンとLLMを組み合わせた6桁のHS2022コードを予測します。

> **免責事項**: 本ライブラリの予測結果はあくまで参考情報です。税関申告の唯一の根拠として使用しないでください。必ず貿易コンプライアンスの専門家または関税当局に確認してください。

---

## 特徴

- **Akinatorスタイルのユーザー体験** — HSコード絞り込みに必要な質問だけを行い、最初から全情報を入力させない
- **ハイブリッドパイプライン** — 混合物GRI → 静的ルールテーブル → SMILES官能基エンジン → LLMフォールバック(優先順位順)
- **物理的形状を考慮したマッチング** — 同一物質でも形状が違えば別HSコード(例: NaOH固体→2815.11、溶液→2815.12)
- **静的ルールテーブル 148エントリ / 133化合物** — 第28・29・38・72〜81類の主要工業化学品
- **SMILES官能基検出** *(v0.3)* — 20官能基、有機/無機分類、ヘディングレベルのヒント(信頼度 ≤ 0.70)
- **SMILES構造特徴エンジン** *(v0.5.1)* — 炭素数・水酸基数・環構造・C=C結合を解析し、ケトン・アルコール・カルボン酸・アルデヒドを**6桁HSサブヘディング**まで解決(信頼度最大0.90)
- **混合物GRI分類** *(v0.5)* — GRI 3a(同一章)、GRI 3b(主成分 >50% w/w)、GRI 3c(数字上最後の見出し)を自動適用。医薬品(第30類)・化粧品(第33類)・食品(第21類)・農薬(第38.08)は用途別ルーティング
- **コンプライアンスリスクフラグ** *(v0.5)*`GrayZone` で第28/29/38類の境界ケースを検出。`PriorConsultation` で事前教示照会を推奨
- **バッチ処理** *(v0.5)*`classify_batch()` / `classify_batch_with_llm()` で複数品目を一括分類
- **IUPAC名→SMILES自動変換**[`chem-name-resolver`]https://crates.io/crates/chem-name-resolver を使用
- **PubChem連携** *(v0.2、`pubchem` フィーチャー)* — CAS/IUPAC/SMILESからの識別子自動補完(決定論的)
- **LLM連携** *(v0.4、`llm` フィーチャー)***Trait hook設計**: 任意のLLMクライアントを実装して接続。ライブラリはプロンプト構築・レスポンス検証を担う
- **WebAssembly対応** *(v0.4)*`hs-predict-wasm` サブクレートでブラウザから直接呼び出し可能
- **統計品目番号** — 実行関税率表2026-04-01に基づく9桁コードを全結果に含む

---

## クイックスタート

### 対話モード(Akinatorスタイル)

```rust
use hs_predict::session::{ClassificationSession, Answer, SessionResult};
use hs_predict::pipeline::HsPipeline;

let mut session = ClassificationSession::new();
let pipeline = HsPipeline::new();

let q = session.start();
println!("{}", q.prompt());
// "CAS番号、IUPAC名、SMILES、InChIKey のいずれかを入力してください"

match session.answer(Answer::Text("1310-73-2".to_string()))? {
    SessionResult::NeedMoreInfo { next_question } => {
        println!("次の質問: {}", next_question.prompt()); // "混合物ですか?"
    }
    SessionResult::Ready => {
        let product = session.to_product_description();
        let prediction = pipeline.classify(&product)?;
        println!("HSコード: {}", prediction.display()); // "28.15.11"
        if let Some(jp) = &prediction.jp_tariff_code {
            println!("統計品目番号: {}", jp);            // "281511000"
        }
    }
    SessionResult::RequiresLlm => { /* llm feature を有効にしてください */ }
}
# Ok::<(), hs_predict::HsPredictError>(())
```

### 日本語セッション

```rust
use hs_predict::session::ClassificationSession;

let mut session = ClassificationSession::new_ja(); // 日本語プロンプト
let q = session.start();
println!("{}", q.prompt()); // "CAS番号、IUPAC名、SMILES、InChIKey のいずれかを入力してください"
```

### ダイレクトモード(CAS番号と形状がわかっている場合)

```rust
use hs_predict::pipeline::HsPipeline;
use hs_predict::types::{ProductDescription, SubstanceIdentifier, PhysicalForm};

let pipeline = HsPipeline::new();

let product = ProductDescription {
    identifier: SubstanceIdentifier::from_cas("1310-73-2"), // 水酸化ナトリウム
    physical_form: Some(PhysicalForm::Solid),
    purity_pct: None,
    purity_type: None,
    mixture_components: None,
    intended_use: None,
    additional_context: None,
};

let p = pipeline.classify(&product)?;
assert_eq!(&p.hs_code, "281511");
assert_eq!(p.display(), "28.15.11");
# Ok::<(), hs_predict::HsPredictError>(())
```

---

## 分類パイプライン

```
入力: ProductDescription
 ┌──────────────────────────────────────────────────────────┐
 │  Priority 0: 混合物GRI分類器      (v0.5)                 │
 │  GRI 3a → 3b (>50% w/w) → 3c;用途別ルーティング        │
 │  (医薬品Ch.30/農薬Ch.38.08/化粧品Ch.33/食品Ch.21)     │
 └──────────────────────┬───────────────────────────────────┘
                        │ 混合物でない場合
 ┌──────────────────────────────────────────────────────────┐
 │  Priority 1: ユーザー提供マッピング  (信頼度 = 1.0)     │
 │  pipeline.with_mapping("64-19-7", "291511")              │
 └──────────────────────┬───────────────────────────────────┘
                        │ ミス
 ┌──────────────────────────────────────────────────────────┐
 │  Priority 2: 静的ルールテーブル    (133化合物)           │
 │  CAS + 形状 + 純度 → 6桁HSサブヘディング                 │
 └──────────────────────┬───────────────────────────────────┘
                        │ ミス
 ┌──────────────────────────────────────────────────────────┐
 │  Priority 3: SMILES構造特徴エンジン (v0.5.1)             │
 │  20官能基 + 構造特徴量                                   │
 │  → ケトン/酸/アルコール/アルデヒドは6桁サブヘディング   │
 │  → その他の官能基はヘディングヒント (信頼度 ≤ 0.70)     │
 └──────────────────────┬───────────────────────────────────┘
                        │ ミス / 低信頼度
 ┌──────────────────────────────────────────────────────────┐
 │  Priority 4: LLM分類器           (v0.4、trait hook)      │
 │  impl LlmClassifier for YourClient { ... }               │
 └──────────────────────┬───────────────────────────────────┘
                   HsPrediction
              { hs_code, confidence, notes,
                gray_zone, recommended_action,
                jp_tariff_code, alternatives }
```

---

## 混合物GRI分類(v0.5)

`ProductDescription::mixture_components` を設定すると、WCO一般解釈規則(GRI)を自動適用します。

| ステップ | 規則 | 条件 |
|---|---|---|
| 0 | 用途別ルーティング | 医薬品→第30類 / 化粧品→第33類 / 食品調製品→第21類 / 農薬→第38.08 |
| 1 | GRI 3a | 全成分が同一章 → 最具体的見出しを採用 |
| 2 | GRI 3b | 主成分 > 50% w/w → その成分の分類を採用 |
| 3 | GRI 3b + LLM | 主成分なし → LLMに委譲(llm feature が必要) |
| 4 | GRI 3c | 数字上最後の見出し;信頼度0.40;`PriorConsultation` 推奨 |

```rust
use hs_predict::types::{ProductDescription, SubstanceIdentifier, MixtureComponent, IntendedUse};
use hs_predict::pipeline::HsPipeline;

let pipeline = HsPipeline::new();

let product = ProductDescription {
    identifier: SubstanceIdentifier::default(),
    physical_form: None,
    purity_pct: None,
    purity_type: None,
    intended_use: Some(IntendedUse::Agricultural),
    mixture_components: Some(vec![
        MixtureComponent {
            substance: SubstanceIdentifier::from_cas("1071-83-6"), // グリホサート
            weight_fraction_pct: Some(41.0),
            volume_fraction_pct: None,
            is_solvent: false,
        },
    ]),
    additional_context: None,
};

let p = pipeline.classify(&product)?;
// 農薬用途 → 3808.xx(第38類)
assert_eq!(p.chapter(), "38");
# Ok::<(), hs_predict::HsPredictError>(())
```

---

## コンプライアンスリスクフラグ(v0.5)

`HsPrediction` に `gray_zone` フィールドが追加され、境界ケースを検出できます。

```rust
use hs_predict::types::{GrayZone, RecommendedAction};

let p = pipeline.classify(&product)?;

match p.gray_zone {
    Some(GrayZone::Chapter29vs38) => {
        // 有機化合物の調製品 — 第29類 vs 第38類を要確認
    }
    Some(GrayZone::MixtureEssentialCharacterUnclear) => {
        // GRI 3c 適用 — 事前教示(binding tariff information)を強く推奨
    }
    _ => {}
}

if p.recommended_action == RecommendedAction::PriorConsultation {
    // 申告前に税関へ事前教示を照会する
}
```

| `GrayZone` バリアント | 意味 |
|---|---|
| `Chapter29vs38` | 有機化合物が用途・調製方法により第38類へシフトする可能性あり |
| `Chapter28vs29` | 有機金属境界 — 金属–炭素結合の有無が分類を決定する |
| `MixtureEssentialCharacterUnclear` | GRI 3c 適用(主成分なし);事前教示を推奨 |

> **事前教示(先例教示)について**: グレーゾーンに該当する場合、最長5年遡及の追徴課税リスクを
> 回避するため、税関へのBinding Tariff Information(事前教示)申請を強く推奨します。

---

## バッチ処理(v0.5)

```rust
let products: Vec<ProductDescription> = vec![/* ... */];

// 同期バッチ(Priority 0〜3)
let results: Vec<Result<HsPrediction>> = pipeline.classify_batch(&products);

// LLMフォールバック付き非同期バッチ(Priority 4)
# #[cfg(feature = "llm")]
let results = pipeline.classify_batch_with_llm(&products).await;
```

---

## SMILES構造特徴エンジン(v0.5.1)

SMILESが利用可能な場合(ユーザー入力またはPubChem補完)、まず構造特徴量(炭素数・水酸基数・環構造・C=C結合)を解析し、主要化合物クラスを**6桁HSサブヘディング**まで解決します。

### 6桁サブヘディング解決

| 化合物クラス || SMILES | HSサブヘディング | 信頼度 |
|---|---|---|---|---|
| アセトン(3C ケトン) | アセトン | `CC(C)=O` | **291411** | 0.87 |
| MEK(4C ケトン) | メチルエチルケトン | `CCC(C)=O` | **291412** | 0.83 |
| MIBK(6C 非環式ケトン) | MIBK | `CC(=O)CC(C)C` | **291413** | 0.80 |
| シクロヘキサノン | シクロヘキサノン | `O=C1CCCCC1` | **291422** | 0.85 |
| アセトフェノン | アセトフェノン | `CC(=O)c1ccccc1` | **291431** | 0.82 |
| エタノール(2C 一価) | エタノール | `CCO` | **220710** | 0.85 |
| エチレングリコール(2C 二価) | エチレングリコール | `OCCO` | **290531** | 0.85 |
| グリセロール(3C 三価) | グリセロール | `OCC(O)CO` | **290541** | 0.85 |
| 酢酸(2C) | 酢酸 | `CC(=O)O` | **291521** | 0.90 |
| プロピオン酸(3C) | プロピオン酸 | `CCC(=O)O` | **291550** | 0.83 |
| アクリル酸(C=C) | アクリル酸 | `OC(=O)C=C` | **291611** | 0.87 |
| メタクリル酸 | メタクリル酸 | `CC(=C)C(=O)O` | **291613** | 0.87 |
| 安息香酸(芳香族) | 安息香酸 | `OC(=O)c1ccccc1` | **291631** | 0.85 |
| ベンズアルデヒド(芳香族) | ベンズアルデヒド | `O=Cc1ccccc1` | **291211** | 0.83 |
| アセトアルデヒド(2C) | アセトアルデヒド | `CC=O` | **291212** | 0.83 |

> **注意:** エタノールは**第22類**(変性していないエチルアルコール、容量80%以上)にルーティングされます。WCO分類実務に準拠した正しい挙動です。

### ヘディングレベルヒント(その他の官能基)

| 官能基 | HSヘディングヒント | 信頼度 |
|---|---|---|
| 酸無水物 | 29.15 | 0.65 |
| イソシアネート | 29.29 | 0.70 |
| ニトリル | 29.26 | 0.70 |
| エポキシド | 29.10 | 0.70 |
| スルホン酸 | 29.04 | 0.68 |
| アミド | 29.24 | 0.67 |
| エステル | 29.15 | 0.55 |
| フェノール | 29.07 | 0.67 |
| アミン | 29.21 | 0.63 |
| 有機ハロゲン化物 | 29.03 | 0.65 |
| エーテル | 29.09 | 0.63 |
| チオール / スルフィド | 29.30 | 0.65 |
| リン酸エステル | 29.20 | 0.62 |
| ニトロ | 29.04 | 0.60 |
| 無機化合物(C–C/C–H結合なし) | 第28類 | 0.55 |

```rust
use hs_predict::smiles::classify_smiles;

let r = classify_smiles("CC(C)=O").unwrap(); // アセトン
assert_eq!(r.heading_hint.heading, Some(2914));
assert_eq!(r.heading_hint.subheading.as_deref(), Some("291411")); // 6桁まで解決!
assert!(r.heading_hint.confidence >= 0.85);

let r = classify_smiles("CCO").unwrap(); // エタノール → 第22類
assert_eq!(r.heading_hint.subheading.as_deref(), Some("220710"));
```

---

## LLM連携 — 設計方針(v0.4)

### なぜTrait hookなのか

HSコードの誤分類は通関申告上の法的・財務的リスクを伴います。LLM APIクライアントをライブラリに直接組み込むと:

- **特定プロバイダーへの依存**(Anthropic、OpenAI など)が生じる
- **コンプライアンス上の非決定性** — 同一品物が呼び出しごとに異なるコードを返すリスク
- **APIキー管理の負担** をライブラリに持ち込む(`Cargo.toml` に機密情報)
- **ネットワーク遅延・障害** を同期的な分類呼び出しに混入させる

代わりに `hs-predict` はTrait hookを定義します。任意のHTTPクライアント・モデル・プロンプトカスタマイズで実装し、ライブラリは構造化された入力と出力検証を提供します。

```rust
// v0.4 — 任意のLLMクライアントでこのtraitを実装
use hs_predict::llm::{LlmClassifier, LlmPrompt, LlmResponse};
use futures::future::BoxFuture;

struct MyClaudeClient { api_key: String }

impl LlmClassifier for MyClaudeClient {
    fn classify<'a>(&'a self, prompt: &'a LlmPrompt) -> BoxFuture<'a, hs_predict::Result<LlmResponse>> {
        Box::pin(async move {
            // 1. prompt.system_text / prompt.user_text を使ってLLM APIを呼び出す
            // 2. JSONレスポンスを LlmResponse に変換(parse_llm_json() ヘルパーが利用可能)
            // 3. ライブラリがhs_codeのフォーマット検証と章整合性チェックを行う
            todo!()
        })
    }
}

// パイプラインに接続 — APIキーはライブラリに保持しない
let pipeline = HsPipeline::new().with_llm(MyClaudeClient { api_key: "...".into() });
let prediction = pipeline.classify_with_llm(&product).await?;
```

ライブラリが提供するもの:
- `LlmPrompt` — 事前構築済みシステムプロンプト + ユーザーメッセージ(製品情報 + SMILESヒント)
- `LlmResponse` — 期待される返却型(`hs_code``confidence``rationale``alternatives`- `PromptBuilder` — EN/JA両対応のプロンプトビルダー
- 6桁コード検証と章整合性チェック
- `MockLlmClassifier``mock` フィーチャー)— テスト用スタブ

---

## WebAssembly対応(v0.4)

`hs-predict-wasm` サブクレートにより、分類エンジン全体をブラウザから呼び出せます。

```bash
cd hs-predict-wasm
wasm-pack build --target web --release
# → pkg/ に JS バインディング生成(約317KB)
```

```js
import init, { classify_smiles, classify_product, WasmSession }
  from './pkg/hs_predict_wasm.js';
await init();

// 1. SMILES直接分類
const r = classify_smiles('CC(O)=O');
// → { organic_class: "organic", heading_hint: { heading: 2915, confidence: 0.6, ... } }

// 2. ルールエンジン全体
const pred = classify_product(JSON.stringify({
  identifier: { cas: "1310-73-2" }, physical_form: "Solid",
  purity_pct: null, purity_type: null, mixture_components: null,
  intended_use: null, additional_context: null
}));
// → { hs_code: "281511", confidence: 1.0, ... }

// 3. Akinatorセッション
const session = new WasmSession();          // または WasmSession.new_ja()
const q = session.start();
// → { step: "Identifier", prompt: "CAS番号...", type: "text" }
const r = session.answer(JSON.stringify({ Text: "1310-73-2" }));
// → { type: "NeedMoreInfo", next_question: { ... } }
// Ready になったら:
const prediction = session.classify();
```

---

## PubChem連携(v0.2)

PubChem連携は不足している識別子フィールドを分類前に補完します。
**事実データの取得**(決定論的)であり、LLMフォールバックとは役割が異なります。

```rust
# #[cfg(feature = "pubchem")]
# async fn example() -> hs_predict::Result<()> {
use hs_predict::pipeline::HsPipeline;
use hs_predict::pubchem::PubChemClient;
use hs_predict::types::{ProductDescription, SubstanceIdentifier, PhysicalForm};

let pipeline = HsPipeline::new().with_pubchem(PubChemClient::new());

let mut product = ProductDescription {
    identifier: SubstanceIdentifier::from_cas("1310-73-2"),
    physical_form: Some(PhysicalForm::Solid),
    purity_pct: None,
    purity_type: None,
    mixture_components: None,
    intended_use: None,
    additional_context: None,
};

pipeline.enrich(&mut product).await?;  // SMILES、InChI、IUPAC名を補完
let prediction = pipeline.classify(&product)?;
println!("{}", prediction.display()); // "28.15.11"
# Ok(())
# }
```

---

## 対話フロー

```
Q1: CAS番号 / IUPAC名 / SMILES / InChIKey を入力してください
     ├─ PubChem自動補完 (pubchem feature) ──────────────────────┐
     │                                                            │
     ▼                                                            ▼
Q2: 混合物ですか?
     ├─ はい ──► Q: 成分は何種類?
     │               └─ 各成分について:
     │                   ├─ Q: 識別子は?
     │                   └─ Q: 重量割合(w/w%)は?
     └─ いいえ ─► Q3: 物理的形状は?
                    (固体 / 粉末 / 顆粒 / 液体 /
                      溶液 / 気体 / 箔 / インゴット / 不明)
                     ├─ 溶液 ──► Q: 濃度(w/w%)は?
                Q4: 用途は?
                    (工業用 / 医薬品 / 農薬 /
                      食品 / 化粧品 / その他)
                     ├─ SMILESなし ──► Q5: 有機/無機/有機金属?
                     │                      │
                     │                      └─ 有機 ──► Q6: 官能基は?
                 分類パイプライン(Priority 1〜4)
```

---

## 対応識別子フォーマット

| フォーマット || 自動検出 |
|---|---|---|
| CAS番号 | `1310-73-2` ||
| IUPAC系統名 | `sodium hydroxide` | ✅(フォールバック) |
| SMILES | `[Na+].[OH-]` ||
| InChI | `InChI=1S/Na.H2O/h;1H/q+1;/p-1` ||
| InChIKey | `HEMHJVSKTPXQMS-UHFFFAOYSA-M` ||

> **注意**: テキスト入力として受け付けるのは **IUPAC系統名のみ** です。俗称・商品名(例:「苛性ソーダ」「カセイソーダ」)は対応していません。

---

## フィーチャーフラグ

| フラグ | 説明 | 追加される依存クレート |
|---|---|---|
| *(なし)* | ルールベース + SMILESエンジン(Priority 1–3) ||
| `pubchem` | PubChem識別子補完 | `reqwest`, `moka`, `governor` |
| `llm` | `LlmClassifier` trait + Pipeline Priority 4 ||
| `mock` | `MockLlmClassifier`(テスト用、llm を含意) ||

```toml
[dependencies]
hs-predict = { version = "0.5.1", features = ["pubchem"] }
```

---

## 静的ルールテーブルの例(133化合物 / 148エントリ)

| CAS番号 | 物質名 | 形状 | HS2022コード |
|---|---|---|---|
| 1310-73-2 | 水酸化ナトリウム | 固体 | 2815.11 |
| 1310-73-2 | 水酸化ナトリウム | 溶液 | 2815.12 |
| 7664-93-9 | 硫酸 | 全形状 | 2807.00 |
| 7697-37-2 | 硝酸 | ≥ 98% | 2808.10 |
| 7697-37-2 | 硝酸 | < 98% | 2808.90 |
| 7664-41-7 | アンモニア | 気体 | 2814.10 |
| 7664-41-7 | アンモニア | 溶液 | 2814.20 |
| 7429-90-5 | アルミニウム | インゴット(純度≥99%) | 7601.10 |
| 7429-90-5 | アルミニウム | 粉末 | 7603.10 |
| 7429-90-5 | アルミニウム || 7607.11 |
| 67-56-1 | メタノール | 液体 | 2905.11 |
| 64-17-5 | エタノール | 液体 | 2207.10 |
| 67-64-1 | アセトン | 液体 | 2914.11 |

全148エントリ(133化合物)は [`src/rules/static_table.rs`](src/rules/static_table.rs) を参照。

---

## ロードマップ

| バージョン | ステータス | 内容 |
|---|---|---|
| 0.1.0 | ✅ リリース済み | コアルールエンジン + Akinatorセッション + 統計品目番号 |
| 0.2.0 | ✅ リリース済み | PubChem API連携 |
| 0.3.0 | ✅ リリース済み | SMILES官能基検出(20種) + Pipeline Priority 3 |
| 0.4.0 | ✅ リリース済み | LLM trait hook + PromptBuilder(EN/JA) + MockLlmClassifier + WASM対応 |
| 0.4.1 | ✅ リリース済み | WAMSコンパニオンクレート + Serialize追加 |
| 0.5.0 | ✅ リリース済み | 混合物GRI分類 · GrayZone · PriorConsultation · 133化合物 · バッチ処理 · セキュリティ強化 |
| 0.5.1 | ✅ リリース済み | SMILES構造特徴エンジン — ケトン・アルコール・カルボン酸・アルデヒドを6桁まで解決(信頼度最大0.90) |
| 0.6.0 | 📋 計画中 | npm公開 · GitHub Actions CI · WASMテスト |

---

## サポートするRustバージョン(MSRV)

Rust **1.75** 以上。

---

## コントリビューション

バグ報告、静的ルールテーブルへの追加、PRを歓迎します。  
静的ルールテーブルへの新規エントリを追加する場合は、HS2022品目表の該当章・号注を引用してください。

---

## ライセンス

以下のいずれかのライセンスのもとで提供されます:

- [MIT License]LICENSE-MIT
- [Apache License 2.0]LICENSE-APACHE

どちらを選んでもかまいません。