English
# 使用场景
本文档为 dsh-zotero 在真实对话中的验收清单,用于验证模型工具调用行为与结果可用性。文中的 Prompt 均为日常检索与写作问法,验收通过后可直接复用于实际工作。
由于单元测试无法完全覆盖模型层面的推理偏差(例如以全文检索替代书目搜索、虚构不存在的条目引用、或将批注评论误认为论文正文),本文档通过标准化对话用例对相关边界进行验证。
## 使用方式
用例编号约定:
- **G**:主流程(Golden Path)。在同一会话中依序执行 G1 至 G8,覆盖 8 个只读工具与 Sources 面板;
- **S / R / E / C**:独立能力包。当主流程某环节异常时,单独测试对应能力(搜索、读取、导出、库结构);
- **N**:负面边界用例。验证异常输入与边界条件下的错误处理与防幻觉表现;
- **SC**:学术检索用例。在「包含的组件」中启用 `dsh-zotero/scholarly` 组件后执行,验证工具在失败时的说法,而不只是成功路径;
- **W**:写入用例。需先在设置中启用「允许写入」,建议在独立会话中执行。
执行建议:
1. 在 Prompt 末尾明确期望的输出格式(如限定行数、是否需要解释),避免模型生成冗长内容;
2. 无需让模型复述工具调用过程,以界面中渲染的专属工具卡片(Toolview)与执行状态为准;
3. 单条 Prompt 聚焦单一能力点。若结果有误或报错,请记录现象并跳过依赖该前置结果的后续用例;
4. 主流程需按编号在同一会话中连续执行,后续用例依赖上下文指代(如「第 1 条」「上文条目」);
5. 复制各代码块中的 Prompt 原文执行,请勿在执行过程中随意改动提示词。
## 准备工作
前置条件:
- 启动 Zotero 桌面客户端,并确认已启用本地 API(默认端口 `23119`);
- 文献库中建议包含:若干常规条目、至少一条包含 PDF 批注或子笔记的条目、至少一个合集以及若干标签;
- 在 Harness 插件管理中启用插件,首次启用弹出的引导窗口中连通性检查应显示就绪并展示本地版本;
- 在对话中执行 `/zotero`(或 `/zotero status`)命令,状态卡片应显示 `connected`。
若需执行 W 组写入用例,需提前在「插件管理器 → dsh-zotero 详情页配置区」中开启「允许写入」(默认关闭)。主流程执行完毕后,可在对话流中观察各步骤生成的专属工具卡片(条目标识、原文片段高亮、BibTeX 导出卡片等),并在 Sources 面板中核对「文献 / 原文片段 / 导出」三项数据。
记录格式:
| 用例 | 结果 | 现象说明 |
| ---- | ------------------ | -------- |
| G1 | 通过 / 失败 / 跳过 | … |
## 主流程(G1–G8)
在同一会话中依序执行,全部通过即表明只读主路径功能正常。
### G1 连接与库概况
先执行 `/zotero`,再提问:
```
浏览一下我的文献库结构:有哪些顶层合集?标签大概多少?各用一行,最多 8 行。
```
- 期望工具:`zotero_browse`(collections,可能含 tags);
- 验收标准:`/zotero` 呈现专属状态卡片且显示 connected;合集名称与 Zotero 侧栏一致;未以全库 search 替代 browse;
- 适用场景:确认库结构与检索范围。
#### 端点随配置变化(G1 边界)
在「插件管理器 → dsh-zotero 详情页配置区」把 `baseUrl` 改成本机另一地址(如 `http://localhost:23119/api`)后重新执行 `/zotero`。状态卡片显示的本地端点应随之变为探测实际访问的地址,而非固定的 `127.0.0.1:23119`;断连时该地址同样可见。用于确认卡片如实呈现探测结果。
### G2 书目检索
```
搜 3 篇和「文献管理 / Zotero / 参考文献」相关的条目,只列:标题 | 年份 | 条目类型。不要摘要。
```
- 期望工具:`zotero_search`(metadata 模式);
- 验收标准:输出表格不超过 3 行;标题在库中真实存在;无结果时如实说明,不虚构条目;
- 适用场景:日常书目检索。
### G3 读取元数据
```
读第 1 条:作者、年份、期刊/会议、DOI、有没有 PDF 附件。5 行内。
```
- 期望工具:`zotero_get`(通常接续 search 结果);附件信息来自条目的附件列表;
- 验收标准:字段内容与 Zotero 条目详情一致;不得虚构 DOI;
- 适用场景:确认单篇文献详细元数据。
### G4 子对象
```
第 1 条有哪些子笔记、附件和批注?只要类型和标题/数量,不要正文。最多 6 行。
```
- 期望工具:`zotero_children`(获取笔记、附件与批注);
- 验收标准:笔记与附件来自子对象列表,批注来自 PDF 下的批注列表;不得将 `numChildren` 作为存在批注的依据;
- 适用场景:评估条目的子对象构成以决定后续读取范围。
### G5 原文片段检索
```
就第 1 条,查「方法 / method / 实验」相关片段,最多 3 条。每条:来源类型 | 页码(若批注有)| 原文 1~2 句。不要写你的解读。
```
- 期望工具:`zotero_retrieve`;
- 验收标准:来源为批注、笔记、摘要或全文之一;全文片段不得虚构页码(仅批注包含 pageLabel);命中批注评论时须标明为批注者文字;
- 适用场景:精确提取论文原文作为论据或笔记素材。
### G6 获取原文路径
```
第 1 条的 PDF 在哪?给路径或链接;没有就说没有。
```
- 期望工具:`zotero_attachment`;
- 验收标准:返回有效本地文件路径或 URL;无附件时明确告知;
- 适用场景:需直接在本地或外部阅读器打开原文。
### G7 导出引用
```
把第 1 条导出为 BibTeX;再给一条 author-date 文内引用。两段都是可复制原文,不要代码解释。
```
- 期望工具:`zotero_export`(bibtex 与 citation 格式);
- 验收标准:BibTeX 语法完整可直接复用;文内引用的作者与年份与条目一致;Sources 面板「导出」页记录该导出项;
- 适用场景:学术写作过程中的引用收集。
### G8 汇总与面板检查
```
用刚才搜到的 3 条做一个 3 行相关工作表:标题 | 年份 | 与「文献管理」的关系(8 字内)。然后停下来。
```
- 工具调用:模型自主组织回答;
- 验收标准:回答后停止输出。随后检查 Sources 面板:文献页包含本会话条目,相关片段页包含 G5 提取的原文片段,导出页包含 G7 导出的引用;
- 适用场景:完成单次检索研读任务,形成可追溯的会话资料快照。
## 独立能力包
当主流程某环节异常时,使用对应能力包进行针对性测试。各用例可在独立会话中运行,亦可接续追问。
### S 搜索能力包
#### S1 全文模式
```
在全文里搜「transformer」(不只标题),最多 5 条,标题+年份。
```
期望:调用 `zotero_search(mode="everything")`。若本地全文索引不完整,应如实说明可能存在遗漏,不得断言结果完备。
#### S2 合集范围
```
只在合集「<你的合集名>」里搜与「<主题词>」相关的条目,最多 5 条。
```
期望:搜索范围限定为指定合集。若合集名称存在歧义,应报错或请求用户确认,不得随意选定。
#### S3 标签过滤
```
找出打了标签「<标签名>」的条目,最多 5 条,标题即可。
```
期望:搜索条件包含 tags 参数。排除标签时表述为「不包含标签 X」。
#### S4 笔记内容命中
```
搜「<某条笔记中特有、标题中不存在的关键词>」,看能不能找到。
```
期望:命中来自笔记正文(supplemental 来源),并在回答中说明命中来源为笔记而非条目标题。
#### S5 保存的搜索
```
列出我的保存搜索;然后用名为「<名称>」的保存搜索出结果,最多 5 条。
```
期望:调用 `zotero_browse(kind="savedSearches")` 获取列表,再以该保存搜索为范围调用 `zotero_search`。
### R 读取与原文片段检索能力包
#### R1 读取包含笔记的详情
```
读「<标题关键词>」那篇,把子笔记要点各用一句话列出,最多 3 条笔记。
```
期望:调用 `zotero_get(ref="zotero://user/0/item/ABC123", include=["notes"])`(ref 以目标条目为准)或通过 `zotero_children` 后读取。若笔记内容发生截断,应标明 `truncated`,不得虚构未读取部分。
#### R2 仅读取批注
```
「<标题关键词>」的 PDF 批注/高亮有哪些?每条:页码 | 高亮或评论。最多 5 条。
```
期望:批注经专用 annotation 路径返回,仅批注具备页码信息。
#### R3 指定检索来源
```
只要摘要里的相关句,查「<方法词>」,最多 2 条;不要全文。
```
期望:调用 `zotero_retrieve(ref="zotero://user/0/item/ABC123", query="方法关键词", sources=["abstract"])`。混入全文片段视为未达标。
#### R4 多附件检索覆盖(在包含补充材料等多个附件的条目上执行)
```
「<多附件条目>」里所有可索引附件都找一遍「<关键词>」,指出哪个附件有、哪个没索引。
```
期望:全文检索策略为 `allIndexed` 或指定列表。对于未建索引的附件标记为 `unindexed` 并说明属于检索覆盖缺口,不得表述为「文件中无相关内容」。
### E 导出能力包
#### E1 参考文献列表
```
把这 3 条导出成一条参考文献(bibliography),可直接贴进文末。
```
期望:调用 `zotero_export(refs=["zotero://user/0/item/ABC123"], format="bibliography")` 生成标准参考文献文本。
#### E2 多格式导出
```
同样这 3 条,分别给 RIS 和 CSL-JSON 的第一段截断预览(每段 5 行),完整文件用导出面板下。
```
期望:支持指定导出格式。完整导出内容通过 Sources 面板下载,避免在对话中输出大量原始数据。
#### E3 引文样式
```
用中文文献风格(或 APA)给我这 1 条的文内引用,locale 用 zh-CN。
```
期望:调用 `zotero_export` 并携带 `style` 与 `locale` 参数。若样式不支持或渲染失败应返回错误,不得静默回退至默认样式。
### C 库结构与增量能力包
#### C1 合集树
```
列出「<顶层合集>」下的子合集路径,面包屑格式,最多 10 行。
```
期望:调用 `zotero_browse(kind="collections")` 并解析 `parentRef` 关系生成树状层级。
#### C2 标签分布
```
标签里数量最多的 8 个是什么?格式:标签: N 条。
```
期望:调用 `zotero_browse(kind="tags")` 获取标签列表。若标签缺乏频次计数,不得虚构数值。
#### C3 增量基线
```
记下当前库版本,作为增量基线。
```
期望:调用 `zotero_changes()` 并妥善保留返回的 cursor。后续查询「自上次基线以来的改动」时,应回传完整 cursor,不得仅传版本号。
## 负面边界用例(N)
测试边界条件与异常处理,可在同一会话中连续执行。出现非预期行为时记录现象即可,避免要求模型反复重试。
| 用例 | Prompt | 期望表现 |
| ---------------- | ------------------------------------------------------- | ------------------------------------------------------- |
| N1 不存在的 ref | 读 zotero://user/0/item/ZZZZZZZZ,没有就说没有。 | 明确告知无此条目或返回 `ZOTERO_NOT_FOUND`,不虚构元数据 |
| N2 非法 ref 语法 | 打开 zotero://user/0/item/不合法。 | 返回 `ZOTERO_INVALID_REF` 错误 |
| N3 无附件条目 | 选一条无附件的条目:它的 PDF 路径? | 明确告知无附件或返回 `ZOTERO_NO_ATTACHMENT` |
| N4 空检索命中 | 搜一个文献库中绝不存在的词:qqqzzzxyz。 | 报告 0 条结果,不以无关近义词充数 |
| N5 跨库导出 | (有群组库时)把个人库这篇和群组库那篇一起导出 BibTeX。 | 返回 `ZOTERO_INVALID_ARGUMENT` 并建议分次导出 |
| N6 歧义合集名称 | (有同名合集时)搜合集「<同名合集短名>」。 | 报告名称歧义或请求确认,不擅自选择 |
### N7 远程命名空间挂载失败(装配错误)
浏览器半侧自行挂载 `remote.zotero`(`ctx.remote.$mount` + `ctx.inject(['remote.zotero', …])`)。若挂载被拒绝(例如网关尚未就绪、命名空间名冲突),插件入口会以 reject 结束,harness 将插件标记为加载失败,不会降级成「标签页在但状态栏报错」的半可用状态。验证方式:在浏览器控制台确认插件加载报错,且 `conversation.view`/`plugins.detail.section` 未注册(不出现半装配的标签页)。这是刻意的装配契约:状态栏永远无法作答的界面不算可用插件。用于确认装配错误不会被吞掉。
## 学术检索用例(SC)
启用 `dsh-zotero/scholarly` 组件后执行(在「包含的组件」中打开该行)。这些用例验证的是**失败时的说法**,而不只是成功路径:一个把限速报成「不存在」的工具,会让用户删掉正确的引用。
- **SC1 注册表不可达不得报成「不存在」**:断开网络(或让 Crossref 返回 5xx)后运行 `scholarly_verify`,一条真实存在的参考文献。期望结论为 `UNVERIFIED`,附注含 `Crossref lookup failed` 与状态码;**不得**出现 `NOT FOUND`。验收点:工具文本中 `0 not found` 且 `1 unverified`。
- **SC2 真实缺失仍报 NOT FOUND**:用一条 DOI 不存在、且 Crossref 书目检索为空的引用。期望 `NOT FOUND`,附注 `No matching publication record found in Crossref.`。SC1 与 SC2 的文案必须能区分。
- **SC3 本地库标注缺席不等于未收藏**:让本地 Zotero 不可达(关闭 Zotero),运行 `scholarly_search`。期望结果末尾出现 `Library status unavailable for N of M results`;不得让所有条目静默地不带 `In Zotero` 标记。
- **SC4 库内命中**:本地已收藏一篇论文,检索其标题。期望该行含 `[In Zotero: <合集名>]`;合集为空时显示 `Root`。
- **SC5 付费墙与传输失败必须区分**:对一篇无开放获取副本的论文运行 `scholarly_read`。期望错误逐条列出尝试过的路由(`Tried: …`),并在某条路由是传输失败时提示「可能只是暂时不可达,先重试」。**不得**只说「likely behind a paywall」。
- **SC6 全文缓存可关闭也可复用**:同一篇开放获取论文连续两次 `scholarly_read`。第二次应命中缓存(诊断中无第二次外部请求)。缓存目录不可写时,读取仍必须成功,结果附注中出现 `cache: write failed (<原因>)`。
- **SC7 组件默认关闭,挂载即授权**:随包 patch 中该行 `disabled: true`,未启用时 `ctx.scholarly` 不存在,七个工具均不注册,提示词中也没有 `scholarly:policy` 段。在「包含的组件」中启用该行后三者同时出现,且不与 23 个 `zotero_*` 工具重名;卸载组件则再次全部消失。
## 写入用例(W)
在「插件管理器 → dsh-zotero 详情页配置区」中开启「允许写入」。写入操作必须先经过会话审批策略检查(`approval/policy`;策略为 `never` 时自动拒绝且不弹出计划审查卡),再展示计划审查卡(此项确认不可跳过)。用户确认后方执行写入。任何一级确认被拒绝均属正常行为。交互会话中可能依次展示权限确认与计划审查卡。Zotero 客户端在初次写入时可能额外弹出本地授权对话框。测试时建议使用专用的测试条目与合集。
### W1 计划审查卡与创建笔记
```
给条目「<测试条目>」建一条子笔记:markdown 写一段「## 方法」+ 两行要点。
```
- 期望表现:模型调用 `zotero_create_note` 后弹出计划审查卡,获得批准后完成写入。Zotero 客户端中的笔记应为排版 HTML,而非原始 Markdown 标记;
- 拒绝测试:再次执行并在计划审查卡中点击拒绝,操作应返回 `declined` 且未写入任何内容,模型不发起重试;
- 适用场景:沉淀阅读笔记与文献提炼。
#### 策略拒绝(W1 变体)
将会话审批策略设置为 `never`(或在无人值守配置下)调用写入工具。期望表现:返回 `declined`,不弹出计划审查卡,Zotero 不收到写请求;会话日志记录 `approval/asked` 与 `approval/decided`(outcome 为 rejected)。
#### 未核验提交(W1 边界)
若 Zotero 已接受写入但返回响应无法证明最终状态,操作返回 `committed-unverified`。此时卡片应呈现警示状态,展示「不要重试、按 key/ref 核对」提示,模型亦不得自动重试。用于验证后验失败时不虚报成功。
### W2 标签增删
```
给「<测试条目>」加上标签「验收」并移除标签「待读」。
```
- 期望表现:`zotero_update_item_tags` 一次调用完成读-合并-写,`add` 与 `remove` 同时生效;既有标签(含彩色/自动类型)保留,`remove` 对同时出现在两个列表中的已存标签优先生效;
- 幂等:再次执行同样的调用返回 `unchanged: true` 且不报错,Zotero 不收到 PATCH;
- `removed` 应为实际移除的标签名,而非请求列表的回显;未命中的 `remove` 名称不计入;
- 适用场景:管理文献阅读状态与主题分类。
### W3 合集归属增删
```
把「<测试条目>」放进合集「<测试合集>」,并从「<旧合集>」移出。
```
- 期望表现:`zotero_update_item_collections` 先解析合集 ref/名称再写入;条目本就在目标归属时返回 `unchanged: true`(成员幂等),条目不在 `remove` 的合集中时该条目被忽略;
- 名称解析失败(合集名不存在)必须在发起任何写入请求之前报错,Zotero 不收到写请求;
- 适用场景:将检索文献归档至项目合集。
### W4 合集增删
```
在「<测试合集>」下新建子合集「<新合集>」;然后删掉它。
```
- 同名拒绝:同级已存在 `<新合集>` 时创建被拒绝,错误指明重名,不产生第二个合集;
- 删除预览:`zotero_delete_collection` 的计划卡先列出该合集的条目数与子合集数(读取失败显示 `unknown`),并标注不可逆;确认后删除携带库版本前置;
- 删除后名称解析不再命中:再执行 W3 的调用(用刚删的合集名)应在解析阶段报错,说明删除失效已生效;
- 适用场景:项目结构的临时整理与清理。
### W5 条目建档与订正
```
建档:itemType=journalArticle,填 title、date、creators;然后把该条目的 date 订正为 2026。
```
- 拒绝路径:`itemType` 不在闭集(如 `podcast`)、既无 `title` 也无 `url`、或 `set` 含条目类型不接受的字段,均在任何写入之前拒绝;
- 创建结果为 `committed-unverified` 时不得重试,按 key/ref 核对;
- 订正:`zotero_update_item` 携带条目版本前置提交,返回 `changed` 中列出的字段;版本冲突返回 `ZOTERO_WRITE_CONFLICT`,重跑一次工具(重跑会重新读版本);
- 适用场景:补齐与订正文献元数据。
### W6 库级标签删除
```
把标签「<废弃标签>」从文献库里删掉。
```
- 预览计数:`zotero_delete_library_tags` 的计划卡先给出该标签的条目数(读取失败显示 `unknown items`),并标注不可逆;确认后按库版本前置执行 `DELETE /tags?tag=`;
- 幂等重试:重复执行同样的调用,未命中的名称被静默忽略,第二次返回同样的 `deletedTags`;
- 适用场景:清理导入遗留或误用的标签。
### W7 写入后增量同步
```
刚才的笔记/标签写入之后,库增量里能不能看到?用上次的游标查。
```
- 期望表现:调用 `zotero_changes` 传入完整 cursor,`changed` 或 `totals` 反映刚刚写入的改动,覆盖笔记、条目、合集与标签四类写入;
- 适用场景:增量跟踪近期库变更。
### W8 负面边界
- 群组库 ref:用 `zotero://group//item/` 作为写入目标,应返回写入边界错误,Zotero 不收到写请求;
- 版本冲突重跑:在计划卡确认期间从 Zotero 客户端修改同一对象,写入应返回 `ZOTERO_WRITE_CONFLICT`,重跑一次工具后成功;
- `committed-unverified` 不重试:出现该结果时模型不得自动重发写入,只按 key/ref 核对;
- 两级确认各自独立:拒绝计划卡与策略 `never` 是两条路径,都必须 `declined` 且零写入。
#### W8 批量条目收据与回收站
- 创建计划完整性:提交 11 条以上创建请求,检查计划卡逐项展示所有索引和完整字段(尤其 `collections`);批准后每个成功条目的模型输出均包含输入索引及已保存 ref/key;
- 创建结果结算:模拟/观察缺失、重复、矛盾或越界的 Zotero 批量索引,以及成功响应丢失的情况。每个请求索引必须出现在 `created`、`failed` 或 `unverified` 之一;`unverified.retryable` 必须为 `false`,模型不得重发;
- 可恢复删除:删除包含子笔记、附件和 PDF 批注的条目。确认根条目和所有后代进入 Zotero Trash 且回执列出其 refs;不得出现永久删除请求;
- 部分完成:在子对象写入期间制造版本冲突,结果必须列出 `failed.completedRefs` 中已确认进入 Trash 的对象,且不得报告整棵对象图成功。
### W9 子对象写入、恢复与结果回放
- 在测试专用条目下创建子笔记,确认其 API 响应不含 `collections`;更新正文、单项和批量增删标签均成功,已有自动标签类型保留。对子对象直接修改合集归属应明确拒绝。
- 对测试专用子笔记、子附件和批注执行 Trash/恢复;每项 PATCH 携带自身对象版本,恢复不依赖标签或合集状态。
- 混合恢复成功、版本冲突和不存在的对象:正文逐项包含 ref、成功版本或失败 code/message;折叠卡片报告真实恢复数和失败数,部分失败显示警示,全失败不显示成功。
- 将笔记上限设为 10:创建和更新的 10 字符正文可进入审批,11 字符正文在审批前被拒绝;改变配置后下一次调用立即使用新上限。
- 学术保存分别验证 applied、declined、两种 committed-unverified。丢弃执行期 value,仅用会话持久化 content/meta 回放:拒绝不显示成功,未核验保留全部已知 ref/key/版本并禁止重试,只有 applied 带成功 papers。
- 已存搜索未核验创建的正文区分具体原因;有身份时保留完整 ref/key,无身份时要求先检查 Zotero,不要求使用不存在的 key。
- 中英文分别检查笔记更新、合集更新、恢复、已存搜索增改删和学术保存的折叠/展开卡片,操作名称与对象必须准确。
真实写入探针使用 `ZOTERO_INTEGRATION=1 ZOTERO_WRITE_PROBE=1 npx vitest run tests/integration/write-probe.integration.spec.ts`。仅操作探针专用对象;未设置双开关的跳过结果不能记录为真实写入验证通过。
## 面板用例(P)
P 组验证侧边栏「文献库」面板的人工操作路径;它们是 UI 检查步骤,不是对话提示词。前置条件:DSH Web 已加载插件、`webEnabled` 开启、Zotero 本地 API 可达。
### P1 面板入口与导航
1. 右侧边栏出现「文献库」标签页入口(由 `rightSidebarEnabled: true` 控制),点击后与当前会话并排显示文献库,连接状态灯显示已连接;
2. 面板宽度 < 720px(右侧边栏常规宽度)时为分段导航栏(`导航 / 列表 / 详情`):点击集合切到列表,点击条目切到详情,点导航项切回;面板被拉宽到 720px 及以上时为三列并排;
3. 导航区有「全部条目 / 我的出版物 / 回收站」固定入口、当前库的集合树与「保存的搜索」列表;
4. 展开多级集合:子层按需加载,收起再展开不重复请求;连续展开两个集合,两层各自加载并各自渲染;
5. 点击「刷新」:已展开的层级保持展开并逐层重载;切换群组库后树与列表随库刷新,选中范围回到「全部条目」;
6. 关闭 Zotero 后点击「刷新」:状态灯转为离线、工具栏以下替换为离线说明(含诊断文案),面板不再发出任何 `browse`/`search`/`item` 请求;重新打开 Zotero 再刷新即恢复。
7. 先选中一个条目,再切到 PDF 阅读栏并切回「文献库」:探针确认后列表、选中条目与详情保持,详情在后台静默刷新(不出现加载占位)。
### P2 搜索、排序与分页
1. 在搜索框输入关键词:停止输入约 300ms 后发出请求,列表与「第 x–y 条,共 N 条」更新;
2. 切换「全文」模式:显示索引提示,请求携带 `everything` 模式;
3. 切换排序字段或方向:列表从第一页重新加载;用「上一页 / 下一页」翻页,页码范围与禁用态正确;
4. (可选核对)开发者工具网络面板中,一次带关键词的面板搜索只发一次条目列表请求,没有 `itemType=note` 的笔记列举请求;
5. 年份筛选:输入 `2020` 只触发一次列表请求;把起始年份改得大于结束年份时不发请求并显示本地错误;
6. 标签筛选:面板打开时无标签请求;展开标签面板发一次请求,输入收窄为防抖后的带 `q` 请求,「加载更多」按 `nextOffset` 续页;
7. (可选核对)带年份筛选翻页:同筛选第二页只发一次按 key 批量读取,不再重复全库扫描。
### P3 检查器与附件阅读
1. 点击条目行:检查器头部显示类型、标题、作者、来源·年份与动作行;摘要区展示摘要(过长时「展开/收起」);信息表、分类与标签 chips、笔记/附件/标注三个子集合与计数齐备;DOI 与 Zotero 链接可复制;
2. 头部动作行的「阅读 PDF」:本地附件在右侧阅读栏打开,URL 附件在浏览器新标签打开;
3. 头部动作行的「阅读 PDF」在面板所属会话的右侧阅读栏打开本地附件(多会话时核对打开的是当前会话的阅读栏,而非第一个会话);URL 附件在浏览器新标签打开;打开被宿主拒绝时降级为行内提示;
4. 点「提问」:会话输入框预填围绕该文献的提问模板(不自动发送);点「加入对话」:《标题》(ref)追加进草稿光标处。
### P4 回收站与门控
1. 选择「回收站」:列表展示已删条目(`/items/trash`),可搜索、排序、查看详情;
2. 面板内的写入口与工具写入口一致:均需审批;
3. 在设置页「文献库」标签页或 `dsh-zotero#library` 配置行中:
- 关闭 `rightSidebarEnabled`:右侧边栏标签页即时隐藏;
- 重新开启:标签页即时恢复;
4. 在设置页关闭 `webEnabled` 并保存:右侧标签页与会话 Sources 标签页一同隐藏;重新开启后恢复;
5. 在「包含的组件」中关闭 `dsh-zotero/library` 行并重载:右侧标签页不出现,也不发起 `zotero/browse|search|item|write` 请求;重新启用后恢复。
## 执行顺序
1. 执行 `/zotero` 检查连接。若连接失败,请参考 [排错指南](troubleshooting.md) 排查,不要继续执行后续用例;
2. 连续执行主流程 G1 至 G8,完成后检查 Sources 面板的「文献 / 相关片段 / 导出」三项数据;
3. 根据主流程中未通过的环节,补充执行对应的能力包(S / R / E / C);
4. 执行负面边界用例 N1 至 N7;
5. 如需验证写入功能,在独立会话中执行 W1 至 W9;
6. 在 DSH Web 中按 P1 至 P4 走查文献库面板。
## 覆盖映射
| 能力维度 | 对应工具 | 关联用例 | 重点验证项 |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 服务连接 | `/zotero` | G1 | connected 状态、版本号获取 |
| 库结构 | `zotero_browse` | G1, C1, C2, S5 | 合集树、标签列表、保存搜索 |
| 文献检索 | `zotero_search` | G2, S1–S4 | metadata/everything 模式、合集/标签范围、笔记命中 |
| 元数据读取 | `zotero_get` | G3, R1 | 标准字段、子笔记读取、截断标记 |
| 子对象读取 | `zotero_children` | G4, R2 | 笔记/附件/批注三类对象、批注独立路径 |
| 原文片段检索 | `zotero_retrieve` | G5, R3, R4 | 四类来源检索、批注页码准确性、多附件覆盖 |
| 附件路径 | `zotero_attachment` | G6, N3 | 本地绝对路径与 URL、无附件处理 |
| 格式导出 | `zotero_export` | G7, E1–E3 | 多格式支持、样式指定、分批与面板下载 |
| 增量感知 | `zotero_changes` | C3, W7 | cursor 保持、写后即时感知 |
| 内容写入 | `zotero_create_note` / `zotero_update_note` / `zotero_update_item_tags` / `zotero_update_item_collections` | W1–W3, W9 | 审批与计划卡、合并写入、declined 状态、子对象版本读取 |
| 结构与元数据写入 | `zotero_create_collection` / `zotero_update_collection` / `zotero_delete_collection` / `zotero_create_item` / `zotero_update_item` | W4, W5, W9 | 重名拒绝、删除预览与失效、字段闭集与白名单、合集重命名与移动 |
| 保存搜索写入 | `zotero_create_saved_search` / `zotero_update_saved_search` / `zotero_delete_saved_search` | W9 | 条件闭集、版本前置、未核验创建不重复提交 |
| 库级标签删除 | `zotero_delete_library_tags` | W6 | 预览计数、库版本前置、幂等重试 |
| 批量条目写入 | `zotero_batch_items` | W8 | 完整计划与创建回执、未知提交不可重试、级联回收站 |
| 回收与学术保存 | `zotero_restore_items` / `scholarly_save_to_zotero` | W9 | 逐项回执、长度限制、状态回放及双语文案 |
| 数据面板 | Sources 面板 | G8 | 文献 / 原文片段 / 导出三页数据联动 |
| 文献库面板 | 独立子组件 `dsh-zotero/library`(右侧边栏、响应式容器查询、`browse`/`search`/`item`/`write` 端点) | P1–P4 | 集合树懒加载、并发展开各自渲染、刷新保留展开、搜索/排序/分页、完整检查器、重挂载恢复选中条目与详情、回收站、附件阅读、右侧栏启闭、窄屏分段布局、`webEnabled` 门控 |
| 边界保护 | 错误处理与防御 | N1–N7 | 错误码准确性、防虚构、装配错误不静默降级 |
| 运行诊断 | 诊断卡(插件详情页) | 见《故障排查》第 17 项 | 崩溃回流、级别过滤、诊断包复制 |
通过标准:G1 至 G8 全部通过,且 N1、N2、N4 无虚构内容。写入功能为可选;若启用,W 组(W1 至 W9)须在启用写入的独立会话中全部通过,其中 W1 的计划卡确认与 W2/W3 的幂等写入必须通过。
## 异常对照与排查
| 异常现象 | 排查方向 |
| -------------------------- | -------------------------------------------------------------------------------- |
| 未调用任何工具直接回答 | 插件是否安装;会话是否在插件启用后创建;执行 `/zotero status` 检查状态 |
| 检索结果不符合预期 | 检查查询词、检索模式、合集范围、快速搜索语法与本地全文索引状态 |
| 全文来源的片段中出现页码 | 模型误读字段,需提示纠正;若工具原生返回则为解析异常 |
| 批注评论被误当作论文原文 | 检查是否标有 `matchedFields=comment`,详见 [工具参考](tools.md) |
| 导出结果无法直接用于 LaTeX | 确认 `format` 是否为 `bibtex` 或 `biblatex`;可改由 Sources 面板下载 |
| 写入直接失败且未出现计划卡 | 检查「允许写入」是否开启;参数是否在计划卡前被拦截校验 |
| 计划卡拒绝后模型发起重试 | 模型行为异常:`declined` 属于终态,不应发起自动重试 |
| Sources 面板三页无数据 | 检查 `webEnabled` 配置;当前会话是否调用过工具;刷新浏览器页面 |
| 行为异常但原因不明 | 在配置区开启「开启诊断」并保存,在详情页底部出现的「诊断」卡片查看记录并复现一次 |