# E2 — 物质类型鉴定插件（plugins/material_id/）

> **定性：可选扩展插件，不随软件本体发布，独立分发，用户按需安装。**
> 本目录职责：加载用户自定义光谱数据库，与输入谱比对，输出相似度排名。
> 只允许修改 `plugins/material_id/` 目录下的文件。
> 继承 PluginInterface（见 `plugins/CLAUDE.md`）。
> 与 L1–L4 完全独立（不共享数据库，不共享代码）。

---

## 识别码（plugin.json）— 必须存在

```json
{
  "plugin_id":       "material_id_v1",
  "name":            "物质类型鉴定",
  "version":         "1.0.0",
  "description":     "加载用户光谱数据库，与输入谱进行相似度比对，输出匹配物质排名",
  "author":          "四川森普力科技有限公司",
  "category":        "光谱分析",
  "entry_module":    "material_id_module",
  "entry_class":     "MaterialIdPlugin",
  "requires_stop":   true,
  "input_type":      "spectrum",
  "output_type":     "json",
  "min_app_version": "1.8.0",
  "builtin":         false
}
```

## Python 元信息（与 plugin.json 保持一致）

```python
PluginInfo(
    plugin_id  = "material_id_v1",
    name       = "物质类型鉴定",
    version    = "1.0.0",
    requires_stop = True
)
```

---

## 鉴定输入范围（重要）

**无论哪种测试类型（常规/扣背景/反射率/透过率/辐照度/拉曼），只对当前屏幕上眼睛「睁开」的谱线执行鉴定。**

| 谱线状态 | 参与鉴定 |
|---------|---------|
| visible=True（眼睛睁开） | ✅ |
| visible=False（眼睛关闭） | ❌ 不参与 |

M0 负责筛选 `S8.get_all()` 中 `visible=True` 的记录，逐条构造 `PluginInput` 传给本插件。

---

## 核心数据结构

```python
@dataclass
class SpectrumRecord:
    record_id: str; name: str; category: str
    data_type: str          # "count" | "irradiance" | "reflectance"
    wavelengths: np.ndarray; intensities: np.ndarray
    notes: str = ""; source: str = ""

@dataclass
class MaterialDatabase:
    db_path: str; db_name: str
    record_count: int; categories: list[str]
    wl_range: tuple[float, float]

@dataclass
class MaterialMatch:
    record: SpectrumRecord
    similarity: float       # 综合（余弦×0.5 + 皮尔逊×0.5）
    cosine_sim: float; pearson_r: float
    rank: int; overlap_nm: float
```

---

## 核心接口（material_id_module.py）

```python
def load_database(db_path: str) -> MaterialDatabase:
    """支持 .db（SQLite）和 .csv 格式。同路径内存缓存，不重复IO。
    加载后设为 self._current_db。"""

def identify(
    wl: np.ndarray, intensities: np.ndarray,
    db: MaterialDatabase,
    top_n: int = 5,
    preprocess: bool = True,
    category_filter: str | None = None
) -> list[MaterialMatch]:
    """算法：Min-Max归一化 → 插值对齐 → cos×0.5 + pearson×0.5。
    重叠 < 50nm 跳过。按 similarity 降序返回 top_n。
    数据库 ≤ 1000 条时耗时 ≤ 2秒。"""

def import_from_csv(
    csv_path: str, db_path: str,
    category: str = "未分类",
    data_type: str = "reflectance",
    force_overwrite: bool = False
) -> int:
    """CSV格式：首列波长，其余列物质（列名=物质名）。返回新增记录数。
    波长列须单调递增，否则 raise ValueError。"""

def export_database(db: MaterialDatabase, export_dir: str, format: str = "csv") -> str: ...
```

---

## SQLite 表结构

```sql
CREATE TABLE spectra (
    id TEXT PRIMARY KEY, name TEXT NOT NULL,
    category TEXT NOT NULL DEFAULT '未分类',
    data_type TEXT NOT NULL,
    wavelengths TEXT NOT NULL,   -- JSON 数组
    intensities TEXT NOT NULL,   -- JSON 数组
    notes TEXT DEFAULT '', source TEXT DEFAULT '',
    created_at TEXT NOT NULL
);
```

---

## 结果颜色标注（界面层 U3 实现）

| similarity | 颜色 | 含义 |
|------------|------|------|
| ≥ 0.90 | 绿色 | 高度匹配 |
| 0.60–0.90 | 黄色 | 中等匹配 |
| < 0.60 | 红色 | 低匹配，仅供参考 |

---

## validate_input 规则

- `self._current_db` 非 None（数据库已加载）
- 输入谱与数据库至少有 50nm 重叠
- 数据点数 ≥ 10

---

## 约束

- 禁止读写 `library/spectra.db`
- 数据库增删须用户手动触发，不自动执行
- 禁止访问 `spectrum_ops/`、`Driver/`、`manager/`
- 禁止对 visible=False 的快照执行鉴定（由 M0 保障，本插件无感知）


---

## 进度文件（必须维护）

本模块进度记录：**`plugins/material_id/PROGRESS.md`**

每完成一个文件立即更新，未更新 `PROGRESS.md` 前不得开始下一个文件。
发现其他模块的问题，记入"跨模块问题"栏，不得顺手修改。

本模块待完成文件清单：
- [ ] `plugin.json`（识别码，必须先创建）
- [ ] `__init__.py`
- [ ] `material_id_module.py`（E2 主逻辑）
- [ ] `databases/default.db`（初始空库）

---

## Agent 状态上报（必须执行）

**本 Agent ID**：`agent-material`
**状态文件**：`{项目根目录}/.agents/agent-material.status.json`
**上报协议**：参阅 `references/agent_protocol.md`

### 关键时机

| 时机 | status 值 |
|------|----------|
| 开始新阶段 | `running` |
| 完成一个文件/功能 | 更新 step + progress |
| 需要用户授权（删除/覆盖/架构决策）| `waiting` + wait_reason |
| 全部完成 | `done`，progress=100 |
| 遇到无法解决的错误 | `error` + 错误说明 |

**写状态样板代码**：参见 `references/agent_protocol.md`

---

## ⛔ Git 提交禁令

**本 Agent 禁止执行任何 git 操作**（`git add`、`git commit`、`git push` 等）。

完成工作后只需：
1. 更新本模块 `PROGRESS.md`
2. 更新根目录 `PROGRESS.md` 的阶段进度
3. 将状态文件写为 `done`（100%）

**Git 提交由总管 Agent 统一执行。**
