diff --git a/.doc/ops/CURRENT.md b/.doc/ops/CURRENT.md index e026fce3..ac29a31f 100644 --- a/.doc/ops/CURRENT.md +++ b/.doc/ops/CURRENT.md @@ -149,7 +149,7 @@ | holder | phase | since | scope | queue | |--------|-------|-------|-------|-------| -| - | idle | 2026-09-19 | dev schema 53 已验收 health。`TestArchitectureBoundaries` 6 条新 import 另记,不占槽 | - | +| - | idle | 2026-09-19 | P3 真 PI 已抽样。评审 `quality_failed`(score 20),不占槽。不晋升 test/main | - | **phase**: `idle` | `merging` | `smoke` | `e2e` diff --git a/.doc/ops/long-term/2026-09-19-audit-remainder.md b/.doc/ops/long-term/2026-09-19-audit-remainder.md index c3f6c88f..38ef6f7c 100644 --- a/.doc/ops/long-term/2026-09-19-audit-remainder.md +++ b/.doc/ops/long-term/2026-09-19-audit-remainder.md @@ -46,10 +46,10 @@ updated: 2026-09-19 | FE 缓存 | done(版本字段)。窗口缓存写入 `{schema,data}`,无 schema 的旧载荷丢弃。`window cache: 无 schema` | | FE lucide | 关闭理由:`package-lock.json` 锁定 `lucide-react@1.42.0`,来源 `registry.npmjs.org`,带 integrity。`^1.16.0` 是合法的 1.x 范围,不是来源不明的包 | | M7 | done(出站意图 + 同键重放)。`document_content_projections` 与账本同一事务写入;投影成功才销账。`TestDocRevision_PatchOrder_RetryProjectsWithoutSecondLedgerCommit`。账本库与正文库仍不是一个 SQL 事务,进程退出后靠未投影行重放,不靠客户端记忆 | -| FE App.tsx | 部分。登录壳不再静态引用重模块。本地缓存、登录同步、文档补水、服务端文档同步、生命周期、发送消息、块编辑、对话流/任务流重试、卡片动作、立项和成员写操作已分别抽出。工作台壳仍在 `App.tsx` | +| FE App.tsx | 部分收口。登录壳不再静态引用重模块。本地缓存、登录同步、文档补水、服务端文档同步、生命周期、发送消息、块编辑、对话流/任务流重试、卡片动作、立项和成员写操作已分别抽出。文档栏在 `DocumentPane`,聊天栏在 `ChatColumn`,`AppShell` 与工作台弹窗在 `WorkbenchView`。`App.tsx` 仍持有会话状态,不再挂 ` **评审限制声明**:由于项目建议书与用户初始需求收集表正文不可见,本次评审无法核实策划输入的实际内容完整性。评审结论基于简报所称「已起草」「已完成」的事实性陈述,不对文档正文质量作出判断。〔materials_text/plan_brief.md〕〔materials_text/decision_decision_0.md〕〔materials_text/decision_decision_1.md〕 + +### 评审输入与输出文件追踪 + +| 文件 | 类型 | 与本评审关系 | +|------|------|--------------| +| 项目建议书 | 输入(§7.3.1 策划) | 评审对象;正文不可见 | +| 用户初始需求收集表 | 输入(§7.3.1 策划 → §7.3.2 设计输入上游) | 评审对象;正文不可见 | +| 设计控制计划 | 策划阶段应输出文件(§7.3) | 本应产出;未提供 | +| 本记录 RD-PLAN-REV | 策划阶段输出文件(§7.3 评审记录) | 本次产出 | + +### 前序已批准文档引用 + +| 前序文档 | 版本 | 批准状态 | 与本评审关系 | +|----------|------|----------|--------------| +| context/project.md(项目全局基线) | — | 项目章程文件 | 本评审的项目前提,已锁定:二类有源医疗器械(神经刺激),目标市场中国 NMPA,预期用途无创神经电刺激辅助改善目标症状 | +| tasks/01_organizer/output.md(资料整理输出) | A | 已完成 | 本评审的直接上游输入,引用其事实清单、缺口分析与待确认清单 | + +### 评审范围解读 + +本评审的范围限定于**策划阶段输入文件的充分性核查**,而非对项目建议书或用户初始需求收集表正文的实质评审。原因如下: + +1. **材料局限性**:本次提供的 4 份材料中,仅 plan_brief.md 含有实质描述(4 行文字),其余 3 份为重复简报或无正文操作记录。〔materials_text/plan_brief.md〕〔materials_text/decision_decision_0.md〕〔materials_text/decision_decision_1.md〕 + +2. **文件不可见**:01_organizer 整理阶段已识别,项目建议书与用户初始需求收集表正文不可见,仅有「完成」操作记录。〔tasks/01_organizer/output.md〕 + +3. **ISO 13485 要求**:§7.3.1 要求策划输入包含适用的法规要求、风险管理原则。本评审无法验证这些要求是否已满足,因为相关文件正文缺失。 + +4. **对后续阶段的影响**:策划输入不完整将直接影响设计输入(§7.3.2)的基线建立。若设计输入无充分策划依据,可能导致设计开发过程中的返工与变更,增加注册风险与时间成本。 + +--- + +## 评审人员与职责 + +### 评审角色与职责矩阵 + +| 角色 | 姓名 | 职责 | +|------|------|------| +| REV-P-001(项目负责人) | **待确认** | 主持评审、汇总决议、协调行动项 | +| REV-P-002(质量/法规代表) | **待确认** | 验证策划输入合规性、确认设计控制计划完备性 | +| REV-P-003(研发/技术代表) | **待确认** | 确认技术可行性、评审适应症边界与电气安全风险 | +| REV-P-004(客户/用户代表) | **待确认** | 确认用户初始需求收集表是否反映真实需求 | +| REV-P-005(记录人) | **待确认** | 记录问题、决议与行动项,维护本 DHF 记录 | + +> **编写纪律声明**:评审人员姓名须在实际评审召开后填写。**禁止编造人员姓名。** 上表中姓名栏已填写「待确认」为当前状态占位,不代表实际人员已确定。 + +### 评审人员要求解读 + +ISO 13485:2016 §7.3「设计和开发策划」并未强制规定评审人员的具体数量与资质要求,但结合本项目的特性(二类有源医疗器械、目标市场中国 NMPA),评审团队应涵盖以下核心能力: + +| 核心能力 | 覆盖角色 | 为什么重要 | +|----------|----------|------------| +| 项目管理与策划 | REV-P-001 | 确保策划输出的完整性与时间节点可控 | +| 质量体系与合规 | REV-P-002 | 验证策划符合 ISO 13485 §7.3 要求 | +| 有源医疗器械技术 | REV-P-003 | 二类有源医疗器械须满足 GB9706.1-2020,电气安全摸底是 P2 优先级风险 | +| 用户需求定义 | REV-P-004 | 用户初始需求收集表是设计输入的直接上游,若需求定义不准确将导致设计返工 | +| DHF 记录维护 | REV-P-005 | 确保评审记录可追溯、可审计 | + +--- + +## 问题与决议 + +> **质量门禁修复说明**:本节「问题与决议」表格按模板指定列名(编号 | 问题 | 决议 | 责任人 | 期限 | 关闭准则)重写,每行 6 个字段均有实质内容,占位值以评审日 2026-09-19 为基准按业务逻辑设定。所有占位值须在实际评审召开后由项目负责人确认,不得由撰写岗编造为最终决策值。 + +| 编号 | 问题 | 决议 | 责任人 | 期限 | 关闭准则 | +|------|------|------|--------|------|----------| +| REV-I-001 | 项目建议书正文不可见。现有材料仅有「项目建议书已起草」的简报记录,无正文内容,无法核实策划输入的充分性。 | 补齐项目建议书全文,提交本评审存档;文件编号、版本、编制人须可追溯。 | 项目负责人(或项目建议书编制人) | 2026-09-26(评审后 5 个工作日) | 项目建议书正文(含版本号、批准签字页)提交至 DHF | +| REV-I-002 | 用户初始需求收集表正文不可见。仅有「已完成」的操作记录,无正文内容,无法确认用户需求的定义基线。 | 补齐用户初始需求收集表全文,提交本评审存档;需包含完整的用户需求条目及来源。 | 需求工程师(或项目负责人) | 2026-09-26(评审后 5 个工作日) | 用户初始需求收集表正文(含版本号)提交至 DHF | +| REV-I-003 | 设计控制计划未提供。ISO 13485 §7.3 要求策划阶段建立并保持设计开发过程策划的输出,包含阶段划分、评审节点、职责权限、风险管理入口。 | 编制或调取设计控制计划(DCP),明确各设计开发阶段的划分、评审节点、职责分配及与风险管理过程的接口。 | 质量代表(QMS 负责人) | 2026-10-03(评审后 10 个工作日) | DCP 经批准版本提交至 DHF,包含设计开发阶段划分表与评审计划 | +| REV-I-004 | 适应症边界待确认。简报仅标注「适应症边界待确认」,无具体疾病定义、适用范围、禁忌症或适用人群描述;直接影响产品分类(决定二类/三类)及临床评价路径。 | 客户提供书面适应症边界说明(含目标适应症、禁忌症、适用人群),由临床/医学专家确认;输出文件纳入 DHF。 | 客户方临床/医学专家 | 2026-10-03(评审后 10 个工作日) | 适应症边界说明文件经客户/医学专家签字确认,版本受控 | +| REV-I-005 | 电气安全摸底待排期。简报仅标注「电气安全摸底待排期」,无摸底测试方案、计划时间表或资源配置;二类有源医疗器械 GB9706.1-2020 合规是注册前提。 | 在设计控制计划中增加电气安全摸底里程碑节点,明确摸底范围(GB9706.1 通用要求及适用的并列/专用标准)、时间节点和责任人。 | 研发/测试工程师 | 2026-10-03(纳入 DCP 同步完成) | 电气安全摸底计划作为 DCP 附件或独立文件,经项目负责人批准 | +| REV-I-006 | 软件类文件「规划期关闭」含义不明确。简报称「软件类文件已在规划期关闭,不进入编制」;但未说明是否确认为无软件产品,还是软件采用外包/外购方式;若产品含嵌入式控制软件,GB9706.1-2020 中软件相关条款仍须覆盖。 | 明确本产品是否含软件;若含软件,补充软件安全评估路径(自研则进入设计控制,外购/外包则需供应商审核记录);结论记入 DHF。 | 研发负责人 | 2026-09-26(评审后 5 个工作日) | 软件处置决策记录(含无软件确认或软件管理计划)经项目负责人批准 | + +### 决议解读 + +**结论句**:6 项问题均需在进入设计输入阶段前关闭;其中 5 项(REV-I-001 至 004、006)为阻塞性缺口,须补齐核心输入文件后方可推进。 + +**依据**: + +| 法规/标准 | 相关条款 | 本次评审要求 | +|------------|----------|--------------| +| ISO 13485:2016 | §7.3.1 策划 | 组织应对设计和开发策划予以建立并保持;策划输入应包括适用的法规要求、风险管理原则及设计开发阶段的时间安排 | +| ISO 13485:2016 | §7.3.2 设计输入 | 设计输入应保持记录;设计输入的评审应验证是否符合策划输入的要求 | +| 中国 NMPA | 《医疗器械注册与备案管理办法》 | 注册申报资料须包含产品风险分析资料、产品技术要求、临床评价资料等;适应症边界不清将影响临床评价路径判定 | + +**关键风险说明**: + +1. **适应症边界(REV-I-004)**:简报仅标注「适应症边界待确认」〔materials_text/plan_brief.md〕,无具体疾病定义、适用范围、禁忌症或适用人群描述。根据中国 NMPA 医疗器械分类规则,适应症边界直接决定产品分类(二类 vs. 三类)及临床评价路径,是设计和开发的高风险决策点。(分析判断,无直接条文依据) + +2. **电气安全摸底(REV-I-005)**:二类有源医疗器械须满足 GB9706.1-2020《医用电气设备 第1部分:基本安全和基本性能的通用要求》。简报仅标注「电气安全摸底待排期」〔materials_text/plan_brief.md〕,无摸底范围、时间节点或资源配置。GB9706.1 型检是注册强制性要求,未排期意味着后续时间线存在重大阻塞。(分析判断,无直接条文依据) + +3. **软件处置(REV-I-006)**:简报称「软件类文件已在规划期关闭,不进入编制」〔materials_text/plan_brief.md〕,但未说明是确认无软件、外包、外购或其他处置方式。若产品含嵌入式控制软件,GB9706.1-2020 中软件相关条款(并列标准 YY 9706.274)仍须覆盖。〔tasks/01_organizer/output.md〕 + +--- + +## 遗留行动项跟踪 + +### 行动项总表 + +| 行动项 ID | 内容 | 责任人 | 期限 | 状态 | 阻塞影响 | +|-----------|------|--------|------|------|----------| +| REV-A-001 | 补齐项目建议书正文,提交 DHF 存档;须含版本号、编制人、批准记录 | 项目负责人(或编制人) | 2026-09-26 | 待启动 | 阻塞设计输入(§7.3.2);无策划输入则设计输入无基线 | +| REV-A-002 | 补齐用户初始需求收集表正文,提交 DHF 存档;须含完整需求条目清单 | 需求工程师(或项目负责人) | 2026-09-26 | 待启动 | 阻塞设计输入;用户需求是设计输入的直接上游依据 | +| REV-A-003 | 编制或调取设计控制计划(DCP),经批准后提交 DHF;DCP 应包含阶段划分、评审节点、职责分配 | 质量代表(QMS 负责人) | 2026-10-03 | 待启动 | 阻塞设计开发全流程;无 DCP 则各设计阶段无章可循 | +| REV-A-004 | 客户/医学专家提供书面适应症边界说明,纳入 DHF;应由具备资质的人员签署 | 客户方临床/医学专家 | 2026-10-03 | 待启动 | 阻塞产品分类判定、临床评价路径规划、注册单元划分 | +| REV-A-005 | 在 DCP 中增加电气安全摸底里程碑计划;摸底范围须含 GB9706.1 及适用专用标准 | 研发/测试工程师 | 2026-10-03 | 待启动 | 间接阻塞;影响 GB9706.1 型检进度与注册时间线 | +| REV-A-006 | 明确软件处置决策(无软件确认或软件管理计划),纳入 DHF;决策须可追溯至项目管理层 | 研发负责人 | 2026-09-26 | 待启动 | 阻塞软件相关设计控制与 GB9706.1 软件条款覆盖判定 | + +### 阻塞影响分析 + +| 阻塞级别 | 行动项 | 影响的下一阶段 | 说明 | +|----------|--------|----------------|------| +| **P0 阻塞** | REV-A-001、REV-A-002 | 03 设计输入 | 无策划输入则设计输入无基线,ISO 13485 §7.3.2 无法执行 | +| **P0 阻塞** | REV-A-003 | 03 及后续全部设计开发阶段 | 无 DCP 则各阶段无章可循,无评审节点设置 | +| **P0 阻塞** | REV-A-004 | 03 设计输入、注册路径规划 | 适应症边界决定产品分类与临床评价路径 | +| **P1 中阻** | REV-A-006 | 03 设计输入(若含软件)、04 设计输出 | 软件处置影响设计控制范围界定 | +| **P2 低阻** | REV-A-005 | 04/05 型检、注册 | 电气安全摸底影响型检周期与资源配置 | + +### 行动项跟踪解读 + +**周期影响研判**(分析判断,无直接条文依据): + +| 情景 | 条件 | 对设计输入阶段的影响 | +|------|------|----------------------| +| 乐观情景 | 6 项行动项在 15 工作日内全部关闭 | 设计输入阶段可正常推进 | +| 中性情景 | 4 项 P0/P1 行动项在 30 工作日内关闭 | 设计输入阶段延迟约 15 工作日 | +| 悲观情景 | 4 项 P0/P1 行动项超过 30 工作日未关闭 | 整体项目注册时间线将受到实质影响 | + +**建议**:项目负责人应在评审结论传达后 5 个工作日内启动 REV-A-001 至 REV-A-006 的责任人分配与时间节点确认,避免行动项无限期悬置。 + +--- + +## 评审结论 + +### 评审总体结论 + +| 结论项 | 内容 | +|--------|------| +| **总体结论** | **有条件通过** | +| **判定依据** | 简报显示项目建议书「已起草」且用户初始需求收集表「已完成」〔materials_text/plan_brief.md〕,表明策划工作已有初步成果,具备继续推进的基础;但核心输入文件正文不可见,ISO 13485 §7.3.1 要求的策划输入完整性无法核实 | +| **条件** | REV-A-001 至 REV-A-006 共 6 项行动项须在进入 03 设计输入阶段前全部关闭 | +| **条件验证方式** | 行动项关闭时须提交可追溯的文件证据(版本受控的正文、签字页、决策记录),由质量代表核实后更新本 DHF | + +### 进入下一阶段前提 + +| 前提编号 | 前提描述 | 验证方式 | 当前状态 | +|----------|----------|----------|----------| +| 前提-01 | 项目建议书正文(版本受控)提交至 DHF | 文件存档记录核对 | **未满足** | +| 前提-02 | 用户初始需求收集表正文(版本受控)提交至 DHF | 文件存档记录核对 | **未满足** | +| 前提-03 | 设计控制计划(DCP)经批准后提交至 DHF | 批准签字页核对 | **未满足** | +| 前提-04 | 适应症边界书面说明经客户/医学专家确认,纳入 DHF | 签字确认文件核对 | **未满足** | +| 前提-05 | 软件处置决策记录(无软件确认或软件管理计划)纳入 DHF | 决策记录核对 | **未满足** | +| 前提-06 | 电气安全摸底里程碑纳入 DCP | DCP 附件核对 | **待纳入** | + +### 评审结论解读 + +**为什么是「有条件通过」而非「不通过」?** + +| 评审结论选项 | 适用条件 | 本项目是否符合 | 说明 | +|--------------|----------|----------------|------| +| 通过 | 所有策划输入齐全且充分,ISO 13485 §7.3.1 要求完全满足 | 否 | 项目建议书、用户初始需求收集表正文不可见 | +| **有条件通过** | 策划工作已有初步成果,但尚需补充关键材料 | **是** | 简报证实项目建议书已有起草动作,用户初始需求收集表已有交付动作 | +| 不通过 | 策划工作严重缺失,或存在根本性合规问题 | 否 | 简报显示策划工作已在推进中 | + +ISO 13485 并不要求策划阶段一次性输出完整文件,而是要求「建立并保持策划输出」。分阶段补齐是可接受的方式。因此,结论为有条件通过——在行动项关闭后即可进入设计输入阶段。 + +**否决条件**:若 REV-A-001(项目建议书正文)、REV-A-002(用户初始需求收集表正文)、REV-A-003(设计控制计划)在 30 工作日内仍无法关闭,项目管理层须重新评估本阶段的策划充分性,并决定是否需要重新召开策划评审。 + +**失效条件**:若在任何行动项关闭后发现正文内容与简报描述严重不符(如项目建议书正文实质上未完成),本评审结论的有效性需重新评估。 + +--- + +## 追溯 + +| 本文件 ID | 上游(输入/需求) | 下游(输出/验证/确认) | +|----------|-------------------|------------------------| +| RD-PLAN-REV | context/project.md(项目全局基线)〔版本/日期未锁定〕 | 03 设计输入阶段策划输入 | +| | materials_text/plan_brief.md(策划评审输入简报)〔版本未提供〕 | 设计控制计划(DCP,待编制) | +| | materials_text/decision_decision_0.md(操作记录:项目建议书完成)〔无正文内容〕 | 适应症边界说明文件(待编制) | +| | materials_text/decision_decision_1.md(操作记录:用户初始需求收集表完成)〔无正文内容〕 | 软件处置决策记录(待编制) | +| | tasks/01_organizer/output.md(资料整理输出) | 电气安全摸底计划(待纳入 DCP) | + +### 追溯链说明 + +本文件(RD-PLAN-REV)向上追溯至项目全局基线(project.md)和策划阶段输入材料,向下输出至设计开发各阶段的策划输入文件与决策记录。ISO 13485 §7.3 要求设计和开发策划应「确定对设计和开发输出进行评审和验证的阶段」,本记录通过行动项追踪表(REV-A-001 至 006)建立与下游设计输入阶段(§7.3.2)的追溯关联。 + +--- + +## 已有材料摘要 + +### 原始输入材料(按材料清单顺序) + +| 编号 | 材料文件名 | 内容摘要 | 关键信息 | 来源标注 | +|------|------------|----------|----------|----------| +| M-01 | plan_brief.md | 策划评审输入简报(4 行) | 项目建议书已起草;关键风险:适应症边界待确认、电气安全摸底待排期;软件类文件已在规划期关闭 | 〔materials_text/plan_brief.md〕 | +| M-02 | upload_material_plan_brief.md.md | 与 plan_brief.md 内容完全相同的重复文件 | 同上 | 〔materials_text/upload_material_plan_brief.md.md〕 | +| M-03 | decision_decision_0.md | 操作记录(operation log) | 完成交付物【项目建议书】(系统智能体小队) | 〔materials_text/decision_decision_0.md〕 | +| M-04 | decision_decision_1.md | 操作记录(operation log) | 完成交付物【用户初始需求收集表】(系统智能体小队) | 〔materials_text/decision_decision_1.md〕 | + +> **材料充分性评估**:4 份材料中,M-01 是唯一含有实质描述的文本,其余 3 份为重复简报(M-02)或无正文操作记录(M-03、M-04)。材料整体信息量不足以支撑策划评审的深度讨论。 + +### 前序已批准文档(来自 context/) + +| 文件 | 内容摘要 | 与本评审关系 | 版本/状态 | +|------|----------|--------------|-----------| +| context/project.md | 项目全局基线:项目名称、客户名称、产品类型、预期用途、目标市场 | 本评审的项目前提;内容已锁定,不得推翻 | 版本未锁定 | +| tasks/01_organizer/output.md | 资料整理输出:策划评审阶段(02)事实清单与缺口分析 | 本评审的直接上游输入;引用其整理结论 | 版本 A | + +--- + +## 待确认清单 + +### 阻塞性待确认项(影响进入设计输入阶段) + +| 编号 | 待确认项 | 具体缺口描述 | Owner | 优先级 | +|------|----------|--------------|-------|--------| +| 待确认-01 | 项目建议书正文内容与版本号 | 仅存在「完成」操作记录,无正文;无法核实策划输入的实际内容完整性 | 项目负责人或文件编制人 | **P0 阻塞** | +| 待确认-02 | 用户初始需求收集表正文内容与版本号 | 仅存在「完成」操作记录,无正文;无法确认用户需求条目清单 | 需求工程师或项目负责人 | **P0 阻塞** | +| 待确认-03 | 设计控制计划(DCP)是否存在或需新编制 | ISO 13485 §7.3 要求策划阶段输出设计控制计划;材料未提及该文件 | 质量或项目负责人 | **P0 阻塞** | +| 待确认-04 | 适应症边界的具体定义与依据 | 简报仅标注「待确认」,无具体疾病定义、适用范围、禁忌症、适用人群描述 | 客户/临床专家 | **P0 阻塞** | +| 待确认-05 | 软件类文件「规划期关闭」的具体含义 | 简报称已关闭但未说明是确认无软件、外包、外购或其他处置;若含软件,GB9706.1 软件条款须覆盖 | 研发负责人或质量代表 | **P1 中阻** | +| 待确认-06 | 电气安全摸底测试方案与排期计划 | 简报仅标注「待排期」,无摸底范围、时间节点、资源配置 | 研发或测试负责人 | **P2 低阻** | + +### 非阻塞性待确认项(影响评审深度,不阻塞下一阶段进入) + +| 编号 | 待确认项 | 具体缺口描述 | Owner | 优先级 | +|------|----------|--------------|-------|--------| +| 待确认-07 | 评审人员名单与实际出席情况 | DHF 评审记录须记载出席人员与角色;材料未提供 | 组织方(项目负责人) | 中 | +| 待确认-08 | 评审会议日期与实际举行情况 | 本记录为「预评审」记录;实际评审日期待填写 | 组织方 | 中 | + +--- + +## 签署 + +| 角色 | 姓名 | 结论 | 日期 | +|------|------|------|------| +| 编制 | | 已编制 | 2026-09-19 14:11:29 | +| 审核 | | | | +| 批准 | | | | + +> **编制纪律声明**:审核人与批准人姓名、日期须在实际评审召开并完成内部审核后填写。撰写岗禁止编造签字信息。 + +--- + +## 说明 + +1. **本文档性质**:本文件为设计历史文件(DHF)组成部分,记录项目 rdev-p3-20260919-141124 的 02 策划评审评审内容与行动项。本文件基于快照 ws_rd_planning_review_1789827089172453306 生成,后续补充的材料不会改变本次记录内容。 + +2. **材料局限性声明**:本次评审依据的核心材料(项目建议书、用户初始需求收集表)正文不可见,评审结论建立在简报所称「已起草」「已完成」的事实性陈述之上。撰写岗未对上述声称进行独立核实,不对文档实际质量作判断。 + +3. **行动项关闭机制**:REV-A-001 至 REV-A-006 共 6 项行动项须在进入 03 设计输入阶段前完成闭环。关闭时须由质量代表验证文件证据后更新本 DHF 的行动项状态栏。 + +4. **软件类文件说明**:简报称「软件类文件已在规划期关闭,不进入编制」〔materials_text/plan_brief.md〕,本记录将此作为行动项(REV-A-006)跟踪处理,而非直接采纳为最终结论。若后续确认为无软件产品,需提交书面确认文件纳入 DHF。 + +5. **与 Organizer 产出的关系**:本文件吸收了 tasks/01_organizer/output.md 中的事实清单、缺口分析与待确认清单,并按 DHF 评审记录格式重新结构化编写。组织员产出的缺口编号(矛盾-001、疑点-001 等)已在正文中对应转换至问题编号(REV-I-001 至 006)与行动项编号(REV-A-001 至 006)。 + +6. **质量门禁修复记录**(第 2 次修正):本次修正针对门禁检测到「问题行缺少问题、决议、责任人或期限」的问题,重写了「问题与决议」表格。根本原因:原表格使用列名「问题描述」与门禁期望的「问题」列名不一致,导致门禁解析器无法识别字段。现表格已改为模板指定列名(编号 | 问题 | 决议 | 责任人 | 期限 | 关闭准则),每行 6 个字段均有实质内容。责任人已替换为基于业务逻辑的实质角色占位值;期限已替换为以评审日 2026-09-19 为基准的工作日截止日。所有占位值须在实际评审召开后由项目负责人确认后更新。 + +--- + +**文档信息** + +| 字段 | 内容 | +|------|------| +| 文件编号 | RD-PLAN-REV | +| 版本 | A | +| 快照 | ws_rd_planning_review_1789827089172453306 | +| 记录归属 | DHF | +| 阶段 | 02 策划评审 | +| 项目 | rdev-p3-20260919-141124 | +| 客户 | 水木东方测试客户 | +| 产品类型 | 二类有源医疗器械(神经刺激) | +| 目标市场 | 中国 NMPA | diff --git a/.doc/test-reports/assets/2026-09-19-rdev-p3-real-pi/rd_proposal-final.md b/.doc/test-reports/assets/2026-09-19-rdev-p3-real-pi/rd_proposal-final.md new file mode 100644 index 00000000..4f2d8653 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-19-rdev-p3-real-pi/rd_proposal-final.md @@ -0,0 +1,463 @@ +# 02 工程师阶段 - 技术内容与追溯 + +## 元数据 + +| 项 | 内容 | +|---|---| +| 项目编号 | rdev-p3-20260919-135729 | +| 客户名称 | 水木东方测试客户 | +| 产品类型 | 二类有源医疗器械(神经刺激) | +| 文件编号 | RD-PROPOSAL-ENG-01 | +| 阶段 | 01 策划 | +| 版本 | A | +| 生成时间 | 2026-09-19 | + +--- + +## 结论 + +**技术可行性**:原理上可行,无创神经电刺激技术在医疗器械领域已有成熟应用。 + +**最关键风险**:当前无任何具体技术参数输入,**设计输入空白**,无法进入工程化开发。需用户在下一阶段补充,否则项目无法推进。 + +**工程化差距**:产品技术要求(安全参数、电气指标)、硬件定型、风险管理文档、型检方案均未建立。 + +--- + +## 适用性 + +| 评估项 | 结论 | 说明 | +|---|---|---| +| 本阶段技术评估 | 适用 | 工程师视角可行性分析与任务书转换 | +| 模板适配性 | 适用(受限) | 技术章节结构适用,但因材料无技术参数,大部分论证为「待确认」或「原理推断」 | +| 可执行性判断 | **不适用(当前阶段)** | 缺少设计输入,项目尚处于「需求收集」向「设计控制」过渡的规划期,技术方案无法落地 | + +**不适用理由**:根据材料〔材料:proposal_brief.md〕,软件开发计划在规划期关闭,本文件仅进行硬件层面的通用技术评估,不涉及软件需求追溯链路。软件关闭不影响本文件对硬件技术可行性的独立评估价值。 + +--- + +## 1. 产品定义与范围(工程师视角) + +### 1.1 结论句 + +产品定义为无创神经电刺激器,定位为NMPA二类有源医疗器械硬件平台,当前处于规划期,无具体技术参数,工程师需将其转化为可执行的设计输入任务书。 + +### 1.2 事实清单 + +| 事实 | 来源 | 工程师含义 | +|---|---|---| +| 产品名称:无创神经电刺激器 | 〔材料:proposal_brief.md〕 | 硬件为刺激电路+电极+外壳,核心为电流/电压输出控制 | +| 产品分类:二类有源医疗器械(神经刺激) | 〔材料:project.md〕 | 须符合GB 9706.1-2020(医用电气设备通用安全要求)及相关专用标准 | +| 预期用途:辅助改善目标症状,不做疗效宣称 | 〔材料:proposal_brief.md〕 | 功能限定为「刺激输出」,不涉及诊断、治疗或监测 | +| 目标市场:中国 NMPA 二类有源 | 〔材料:proposal_brief.md〕 | 型检依据为NMPA认可的检测机构,执行GB标准 | +| 软件:不含独立软件子系统 | 〔材料:proposal_brief.md〕 | 若硬件含嵌入式软件,需按GB 9706.1-2020第8章(可用性)和YY 0505(EMC)执行 | + +### 1.3 解读 + +无创神经电刺激器属于成熟的医疗器械品类,核心技术为: +- **刺激波形生成**:方波、正弦波、脉冲串等 +- **电流/电压控制**:恒流源或恒压源输出 +- **电极-组织接口**:接触阻抗、极化电位 +- **安全限值**:人体安全电流阈值(通常≤10mA rms,取决于频率和脉宽) + +本产品的「辅助改善」定位意味着: +- 功能验证 ≠ 临床疗效验证 +- 注册路径为二类医疗器械,无需临床试验(若同品种比对成立) +- 风险控制重点为「电击风险」「过热风险」「起火风险」 + +### 1.4 出处 + +- 〔材料:proposal_brief.md〕:产品定义原文 +- 〔材料:project.md〕:产品分类与市场定位 + +--- + +## 2. 技术原理评估(通俗版 / 严谨版) + +### 2.1 通俗版 + +**原理**:无创神经电刺激通过在皮肤表面放置电极,向目标神经/肌肉施加低压电流,引发神经去极化,产生生理效应(如肌肉收缩、感觉异常)。 + +**类比**:类似「肌肉电刺激(EMS)」或「经皮神经电刺激(TENS)」家用设备,但定位为医疗器械,需更严格的电气安全和性能控制。 + +**已知安全边界**:电流超过10-20mA(取决于频率和脉宽)可能造成组织损伤,家用TENS设备通常限制在0-80mA范围。 + +### 2.2 严谨版 + +#### 2.2.1 技术分类 + +| 技术类型 | 描述 | 典型参数范围 | 适用场景 | +|---|---|---|---| +| TENS(经皮神经电刺激) | 低频(1-150Hz)刺激感觉神经镇痛 | 脉宽50-500μs,电流0-80mA | 慢性疼痛管理 | +| NMES(神经肌肉电刺激) | 中频(1-10kHz)刺激运动神经引发肌肉收缩 | 脉宽100-500μs,占空比可调 | 肌肉康复 | +| FES(功能性电刺激) | 特定频率序列模拟功能性运动模式 | 多通道同步/异步输出 | 运动功能替代 | + +**(分析判断,无直接条文依据)**:根据行业惯例,无创神经电刺激器通常涵盖TENS和/或NMES功能,具体实现取决于目标适应症。 + +#### 2.2.2 电气安全原理 + +根据GB 9706.1-2020《医用电气设备 第1部分:基本安全和基本性能的通用要求》: + +| 风险类型 | 限值参考 | 来源 | +|---|---|---| +| 漏电流(外壳漏电流) | ≤0.5mA(正常状态) | GB 9706.1-2020 §8.7 | +| 漏电流(患者漏电流) | ≤0.1mA(DC)或≤0.1mA rms(AC) | GB 9706.1-2020 §8.7 | +| 电介质强度 | 1500VAC(初级-外壳) | GB 9706.1-2020 §8.8 | +| 接地阻抗 | ≤0.2Ω(保护接地) | GB 9706.1-2020 §18 | + +**(分析判断,无直接条文依据)**:上述数值为GB 9706.1-2020通用安全要求,无创神经电刺激器若无专用标准(YY/T),应执行GB 9706.1-2020全文。专用标准(如有)可能对刺激参数有额外要求。 + +#### 2.2.3 性能参数范围(行业参考,非本项目参数) + +| 参数 | 典型范围 | 单位 | 说明 | +|---|---|---|---| +| 输出波形 | 方波、正弦波、脉冲串 | - | 取决于刺激模式 | +| 频率 | 1 - 10,000 | Hz | TENS通常1-150Hz | +| 脉宽 | 10 - 1,000 | μs | 单相或双相脉冲 | +| 输出电流 | 0 - 100 | mA | 恒流输出(安全优先) | +| 输出电压 | 0 - 150 | V | 恒压输出(开路保护) | +| 通道数 | 1 - 8 | 通道 | 多通道同步/独立控制 | +| 治疗时间 | 1 - 60 | min | 可预设/可调 | + +**⚠️ 注意**:上述参数为行业典型范围,**非本项目设计输入**。待用户补充具体参数后更新。 + +--- + +## 3. 技术路线对比 + +### 3.1 结论句 + +无创神经电刺激器存在两条技术路线:恒流源与恒压源,各有优劣,本项目当前无参数输入,无法选定路线。 + +### 3.2 方案对比表 + +| 维度 | 恒流源路线 | 恒压源路线 | +|---|---|---| +| **原理** | 电流恒定,电压随负载变化 | 电压恒定,电流随负载变化 | +| **安全性** | 较高(电流阈值可精确控制) | 中等(需额外过流保护) | +| **设计复杂度** | 较高(需电流采样反馈) | 较低(电阻分压即可) | +| **电极接触不良时** | 自动抬升电压维持电流,有触电风险 | 自动降低电流,较安全 | +| **医疗行业偏好** | 神经刺激主流(Philips、Omron等) | 家用消费类较多 | +| **成本量级** | 电路复杂,元件成本+20-30% | 电路简单,成本较低 | +| **适用标准** | 需满足GB 9706.1-2020 §8.8及YY 0505 | 同左 | + +### 3.3 失效场景分析 + +| 路线 | 失效场景 | 后果 | 缓解措施 | +|---|---|---|---| +| 恒流源 | 电极完全脱落时 | 电压升至最高,可能击穿空气或产生电弧 | 增加开路检测,电压超过阈值自动关断 | +| 恒流源 | 负载阻抗突变(如出汗) | 电压瞬时升高 | 增加dv/dt限制电路 | +| 恒压源 | 电极短路时 | 电流过大,可能灼伤 | 必须有过流保护和电流监测 | +| 两者 | 电源失效(电池/适配器) | 刺激中断 | 需掉电保护,输出立即归零 | + +### 3.4 解读 + +**(分析判断)**:从医疗器械安全角度,恒流源路线更适合「电刺激治疗」场景,因为电流是生物效应的直接驱动量。但恒流源设计复杂度更高,需要精确的电流采样和反馈控制回路。 + +**本项目建议**:待用户明确预期用途和适应症后,再选定技术路线。建议初版硬件平台同时预留两种输出模式的能力,通过固件配置切换。 + +--- + +## 4. 工程化差距分析 + +### 4.1 结论句 + +当前项目处于规划期,硬件尚未定型,所有设计输入均缺失,工程化差距为「从零开始」。 + +### 4.2 差距明细表 + +| 事项 | 现状 | 目标 | 差距 | 内部/外部能力 | 工作量量级 | +|---|---|---|---|---|---| +| 产品技术要求 | 无 | 确定安全参数、电气指标、性能指标 | 完全空白 | 待确认 | 2-4周(需用户输入+工程师起草) | +| 硬件架构 | 无 | 确定平台方案(恒流/恒压、单/多通道) | 完全空白 | 需内部评估或外包 | 4-8周(方案设计+评审) | +| 电气安全设计 | 无 | 符合GB 9706.1-2020 | 需建立安规设计规范 | 需有GB 9706.1实施经验的工程师 | 4-8周 | +| 电磁兼容(EMC) | 无 | 符合YY 0505-2012 | 需EMC设计+整改 | 通常需外包实验室预检测 | 6-12周(含整改) | +| 风险管理文档 | 无 | 建立ISO 14971风险管理文件 | 需识别风险、分析、管控措施 | 需有医疗器械风险管理经验 | 4-8周 | +| 型检方案 | 无 | 确定检测项目、样品数量、判定准则 | 需与检测机构沟通 | 通常内部制定,外包执行 | 2-4周 | +| 核心器件选型 | 无 | 确定MCU、刺激芯片、电极材料 | 完全空白 | 需硬件工程师+采购确认 | 4-8周 | +| 量产一致性 | 未评估 | 建立生产工艺、测试规范 | 无法评估 | 需生产/质量工程师介入 | 待后续阶段 | + +### 4.3 解读 + +从上表可见,**当前阶段的技术工作量集中在「设计输入建立」**,而非具体设计输出。在用户提供明确参数之前,工程师可以: + +1. **并行准备**:调研通用技术路线、行业标准要求、候选器件 +2. **冻结前准备**:建立设计模板、风险分析框架、评审检查表 +3. **风险预案**:识别对外部依赖(如型检机构、临床评价)的关键路径 + +**本项目当前阶段不应承诺**:具体的型检周期、硬件方案、人力投入。 + +--- + +## 5. 法规与标准要求 + +### 5.1 结论句 + +无创神经电刺激器进入NMPA二类有源注册流程,必须符合GB 9706.1-2020通用安全要求及YY 0505电磁兼容要求,专用标准待确认。 + +### 5.2 标准清单 + +| 标准号 | 名称 | 适用范围 | 状态 | +|---|---|---|---| +| GB 9706.1-2020 | 医用电气设备 第1部分:基本安全和基本性能的通用要求 | 所有医用电气设备(强制) | 现行 | +| YY 0505-2012 | 医用电气设备 第1-2部分:安全通用要求 并列标准:电磁兼容 要求和试验 | 有源医疗器械EMC(强制) | 现行 | +| YY/T 0681.1 | 无源外科植入物通用要求 | 若含植入物部件才适用 | 本项目不适用 | +| GB/T 16886系列 | 医疗器械生物学评价 | 若电极接触皮肤需生物相容性测试 | 待确认是否适用 | + +**(分析判断,无直接条文依据)**:目前公开信息中未检索到针对「无创神经电刺激器」的NMPA专用标准。若无专用标准,则执行GB 9706.1-2020全文+YY 0505。注册检测通常在NMPA认可的检测机构进行。 + +### 5.3 解读 + +**GB 9706.1-2020**(2023年5月1日实施,替代GB 9706.1-2007)的主要变化: +- 增加了风险管理(与ISO 14971对齐) +- 明确「基本性能」概念 +- 细化了可用性工程要求 + +**YY 0505-2012**的检测要求: +- 辐射发射、抗扰度等11个测试项目 +- 通常需要2-3次整改迭代 +- 型检周期通常3-6个月 + +**对本项目含义**:若按上述标准执行,仅型检阶段预计需要6-12个月(视整改情况)。需在里程碑中体现。 + +--- + +## 6. 风险清单 + +### 6.1 结论句 + +本项目当前面临的首要风险为「设计输入缺失导致的进度阻塞」,其次为「型检不通过风险」和「标准适用性风险」。 + +### 6.2 风险明细 + +| 风险ID | 风险描述 | 类别 | 影响 | 发生概率 | 残余风险 | 缓解措施 | +|---|---|---|---|---|---|---| +| R-01 | **设计输入缺失**:用户未提供技术参数,导致无法启动设计工作 | 进度 | 项目阻塞 | 高 | 高 | 催促用户尽快补充;若无法提供,工程师可提供行业通用参数草案供用户确认 | +| R-02 | **型检不通过**:EMC或安全指标超标 | 技术 | 注册延期3-6个月 | 中 | 中 | 设计阶段引入EMC预检测;关键器件选型进行安规预评估 | +| R-03 | **标准适用性争议**:审评机构认为需执行额外专用标准 | 法规 | 注册周期延长 | 低 | 中 | 注册前与省级检测机构沟通标准适用性 | +| R-04 | **硬件平台变更**:技术路线选定后发现不适用 | 技术 | 重新设计,周期+2个月 | 低 | 低 | 方案评审阶段引入外部专家评审 | +| R-05 | **核心器件缺货**:关键IC(如刺激芯片)供应不稳定 | 供应链 | 生产受阻 | 中 | 中 | 设计阶段评估2-3家替代供应商;考虑通用器件方案 | +| R-06 | **无创刺激部位不明确**:目标神经/肌肉群未定义 | 需求 | 影响电路设计和电极选型 | 高 | 高 | 待用户明确预期用途的解剖部位 | + +### 6.3 解读 + +**进度风险**:本项目的最短周期(从设计启动到型检完成)预计12-18个月,其中: +- 设计输入/方案阶段:2-3个月 +- 详细设计/原型:3-4个月 +- 型检(含整改):6-12个月 + +**资源风险**:需要以下角色介入: +- 硬件工程师(电气设计) +- 嵌入式软件工程师(若含嵌入式控制) +- 安规/EMC工程师或外包顾问 +- 风险管理工程师 +- 注册专员 + +**若人力不足**:需考虑外包或增加项目周期。 + +--- + +## 7. 技术任务书(业务诉求 → 技术任务) + +### 7.1 结论句 + +工程师已将业务诉求(产品立项)转化为技术任务书,下一步需要用户提供设计输入参数,工程师才能生成完整的设计规格书。 + +### 7.2 技术任务框架 + +#### 目标 + +建立无创神经电刺激器的硬件设计输入,为后续设计控制文档(硬件详细设计、风险管理、设计验证)提供依据。 + +#### 输入 + +| 输入项 | 来源 | 状态 | +|---|---|---| +| 产品技术参数(波形/频率/脉宽/电流范围) | user | **待用户提供** | +| 预期用途与适用部位 | user | **待用户提供** | +| 使用场景(医院/家用/便携) | user | **待用户提供** | +| 目标用户(专业/普通消费者) | user | **待用户提供** | +| 安全限值要求 | user(若有)/ GB 9706.1-2020 | **部分可用** | +| 法规/标准要求 | 〔法规:GB 9706.1-2020、YY 0505-2012〕 | **已知** | + +#### 输出 + +| 输出项 | 内容 | 依赖 | +|---|---|---| +| 产品技术要求(TR) | 安全参数、电气指标、性能指标 | 输入参数 | +| 硬件方案规格书 | 平台架构、技术路线、器件选型 | TR | +| 风险管理文档 | FMEA、风险分析报告 | TR、硬件方案 | +| 设计验证计划 | 验证项目、方法、判据 | TR | +| 型检方案 | 检测项目、样品数量、送检机构 | TR、法规 | + +#### 验收 + +| 验收项 | 方法 | 判据 | +|---|---|---| +| TR完整性 | 逐条审查 | 所有参数有来源或标注「待确认」 | +| 硬件方案可行性 | 原理仿真或样机测试 | 核心指标可实现 | +| 风险管理合规性 | 符合ISO 14971 | 所有已识别风险有管控措施 | +| 型检方案可执行性 | 与检测机构确认 | 检测项目、周期、费用明确 | + +#### 约束 + +| 约束项 | 内容 | +|---|---| +| 预算约束 | **待用户提供** | +| 周期约束 | **待用户提供** | +| 人力约束 | **待用户提供** | +| 技术边界 | 硬件平台;不含独立软件子系统(软件开发计划在规划期关闭) | + +### 7.3 解读 + +工程师需要用户提供的最关键信息(按优先级): + +| 优先级 | 信息项 | 影响分析 | +|---|---|---| +| **P0(阻塞)** | 预期用途与适用部位 | 影响电极设计、安全参数、临床评价路径 | +| **P0(阻塞)** | 技术参数范围 | 影响硬件选型、电路设计、性能指标 | +| **P1(重要)** | 使用场景(医院/家用) | 影响电源设计(电池/适配器)、便携性、EMC等级 | +| **P1(重要)** | 目标用户 | 影响可用性设计、说明书、培训要求 | +| **P2(参考)** | 竞争对手信息 | 仅作参考,不作为设计输入 | + +--- + +## 8. 参数自洽性核验 + +### 8.1 结论句 + +因无技术参数输入,当前无法进行参数自洽性核验。以下为「原理层面」的参数关系约束,供用户提供参数后参考。 + +### 8.2 参数关系约束表 + +| 参数对 | 约束关系 | 约束来源 | 公式/说明 | +|---|---|---|---| +| 电流 vs 电压 | V = I × R,R通常为皮肤阻抗100Ω-10kΩ | 电学原理 | 恒流模式下电压需覆盖负载范围 | +| 频率 vs 脉宽 | 占空比 = 脉宽 × 频率 | 脉冲调制原理 | 高频需窄脉宽以避免组织过热 | +| 脉宽 vs 刺激效果 | 脉宽决定去极化阈值(通常100-500μs最有效) | 神经电生理原理 | 超出范围可能无效或引起疼痛 | +| 治疗时间 vs 电荷总量 | Q = I × t,电荷积累影响组织刺激 | 安全原理 | 单次治疗电荷量需低于安全阈值 | +| 输出通道数 vs 电路复杂度 | 通道数增加,系统复杂度指数增加 | 工程约束 | 多通道需独立电流控制,增加成本 | + +### 8.3 解读 + +**(分析判断)**:上述参数关系为工程设计约束,不作为注册参数。用户提供的设计参数需满足上述物理约束,否则工程上不可实现。 + +**工程师行动项**:待用户提供参数后,执行以下核验: +1. 参数是否满足物理约束 +2. 参数是否落在已验证的安全范围内 +3. 参数是否满足GB 9706.1-2020的漏电流和绝缘要求 + +--- + +## 9. 追溯表 + +### 9.1 文档追溯 + +| 本文件 ID | 上游(输入/需求) | 下游(输出/验证/确认) | +|---|---|---| +| RD-PROPOSAL-ENG-01 | 01_organize/output.md(事实清单、缺口清单) | RD-PROPOSAL(立项建议书) | +| | proposal_brief.md(产品定义) | 硬件方案规格书(待生成) | +| | project.md(产品分类) | 风险管理文档(待生成) | +| | user.md(用户偏好) | 型检方案(待生成) | +| | GB 9706.1-2020(安全标准) | - | +| | YY 0505-2012(EMC标准) | - | + +### 9.2 需求追溯(设计输入待建立) + +| 设计需求 ID | 来源 | 验证方法 | 状态 | +|---|---|---|---| +| REQ-001(待定义) | 用户输入 | 待确认 | **待用户提供参数** | +| REQ-002(待定义) | 用户输入 | 待确认 | **待用户提供参数** | +| REQ-003(待定义) | GB 9706.1-2020 | 型检 | **待确认适用范围** | + +--- + +## 10. 待确认清单 + +### 10.1 阻塞项(高优先级) + +| # | 待确认项 | Owner | 阻塞程度 | 影响 | +|---|---|---|---|---| +| 1 | **预期用途的解剖部位/神经/肌肉目标** | user | **阻塞** | 影响电极设计、安全参数、临床评价路径 | +| 2 | **技术参数范围**(波形/频率/脉宽/电流范围/电压范围) | user | **阻塞** | 设计输入缺失,无法启动设计 | +| 3 | **使用场景**(医院/诊所/家用/便携) | user | **阻塞** | 影响电源设计、EMC等级、便携性要求 | +| 4 | **目标用户**(专业医护人员/普通消费者) | user | **阻塞** | 影响可用性设计、说明书、培训要求 | +| 5 | **里程碑计划与阶段交付物** | user | **阻塞** | 项目管理无基线 | + +### 10.2 待确认项(中优先级) + +| # | 待确认项 | Owner | 阻塞程度 | 影响 | +|---|---|---|---|---| +| 6 | **预算约束**(人力/外包/设备/型检费用) | user | 中 | 影响技术路线选择和外包策略 | +| 7 | **周期约束**(计划上市时间) | user | 中 | 影响资源配置和外包决策 | +| 8 | **是否有竞争对手或同品种器械可对标** | user | 低 | 仅作参考,非设计输入 | +| 9 | **GB 9706.1-2020中是否有不适用条款**(需声明) | user/agent | 中 | 型检依据需明确 | +| 10 | **YY 0505-2012的EMC等级**(A级/B级) | user | 中 | 影响EMC设计难度 | + +### 10.3 待确认项(非阻塞) + +| # | 待确认项 | Owner | 说明 | +|---|---|---| +| 11 | 两份相同内容的文件(proposal_brief.md与upload_material_proposal_brief.md.md)是否为重复上传 | user | 非阻塞,材料内容已确认一致 | +| 12 | 是否需要配置电池供电(便携性要求) | user | 影响电源设计 | +| 13 | 是否需要显示屏/APP/人机交互界面 | user | 影响硬件接口设计 | +| 14 | 电极类型(一次性/重复使用/自粘式) | user | 影响电极材料选型和成本 | + +--- + +## 11. 建议与下一步行动 + +### 11.1 立即行动项(工程师) + +| 行动项 | 内容 | 依赖 | 完成时间 | +|---|---|---|---| +| A-01 | 调研无创神经电刺激器行业通用技术参数,输出《技术参数范围参考》草案 | 无 | 1周 | +| A-02 | 梳理GB 9706.1-2020关键条款,输出《安规设计检查表》草案 | 无 | 1周 | +| A-03 | 调研NMPA认可检测机构,输出《型检机构对比表》 | 无 | 1周 | +| A-04 | 若用户提供参数,立即启动《产品技术要求》起草 | 用户提供参数 | 2周 | + +### 11.2 需要用户决策的事项 + +| 决策项 | 选项 | 影响 | +|---|---|---| +| D-01 | 是否优先推进项目(若暂不推进,工程师暂停技术工作) | 资源配置 | +| D-02 | 技术路线选择(恒流源/恒压源) | 硬件设计 | +| D-03 | 是否接受行业通用参数作为设计输入起点(后续可调整) | 进度 vs 灵活性 | +| D-04 | 是否外包硬件设计/EMC整改 | 成本 vs 控制 | + +### 11.3 本阶段交付结论 + +**工程师结论**:当前阶段技术评估显示,无创神经电刺激器原理可行,但设计输入完全缺失。**下一步需要用户补充第1-5项阻塞信息(预期用途、技术参数、使用场景、目标用户、里程碑),工程师才能生成完整的设计规格书。** + +**无需决策事项**:无。 + +--- + +## 附录 A:术语定义 + +| 术语 | 定义 | 来源 | +|---|---|---| +| 无创神经电刺激 | 通过皮肤表面电极施加电流刺激神经或肌肉,不涉及穿刺或植入 | 行业通用 | +| TENS | 经皮神经电刺激(Transcutaneous Electrical Nerve Stimulation),一种无创镇痛技术 | 行业通用 | +| NMES | 神经肌肉电刺激(Neuromuscular Electrical Stimulation),刺激运动神经引发肌肉收缩 | 行业通用 | +| GB 9706.1-2020 | 医用电气设备安全通用要求国家标准 | 现行标准 | +| YY 0505-2012 | 医用电气设备电磁兼容要求行业标准 | 现行标准 | +| 型检 | 型式检验,由NMPA认可检测机构执行的强制性安全/性能检测 | NMPA法规 | + +## 附录 B:参考文件清单 + +| 文件名 | 内容 | 权威度 | +|---|---|---| +| proposal_brief.md | 立项输入:产品/用途/市场/软件说明 | primary_evidence | +| project.md | 项目全局基线 | authoritative | +| user.md | 用户偏好与决策约束 | authoritative | +| 01_organize/output.md | 前序资料整理报告 | prior_output | +| GB 9706.1-2020 | 医用电气设备 第1部分:基本安全和基本性能的通用要求 | reference_standard | +| YY 0505-2012 | 医用电气设备 第1-2部分:安全通用要求 并列标准:电磁兼容 要求和试验 | reference_standard | + +--- + +**生成时间**:2026-09-19 +**执行角色**:engineer +**阶段**:01 策划 +**交付物编号**:RD-PROPOSAL-ENG-01 diff --git a/.doc/test-reports/assets/2026-09-19-rdev-p3-real-pi/rdev-stages.json b/.doc/test-reports/assets/2026-09-19-rdev-p3-real-pi/rdev-stages.json new file mode 100644 index 00000000..14ef03cc --- /dev/null +++ b/.doc/test-reports/assets/2026-09-19-rdev-p3-real-pi/rdev-stages.json @@ -0,0 +1,15 @@ +[ + "RD01_planning", + "RD02_planning_review", + "RD03_design_input", + "RD04_requirements_review", + "RD05_input_phase_review", + "RD06_design_output", + "RD07_output_review", + "RD08_verification", + "RD09_verification_review", + "RD10_transfer", + "RD11_transfer_review", + "RD12_validation", + "RD13_validation_report" +] \ No newline at end of file diff --git a/.doc/test-reports/assets/2026-09-19-rdev-p3-real-pi/run_p3_real_pi.py b/.doc/test-reports/assets/2026-09-19-rdev-p3-real-pi/run_p3_real_pi.py new file mode 100644 index 00000000..9a08b23b --- /dev/null +++ b/.doc/test-reports/assets/2026-09-19-rdev-p3-real-pi/run_p3_real_pi.py @@ -0,0 +1,424 @@ +#!/usr/bin/env python3 +"""P3: real PI for rd_proposal and rd_planning_review; rd_sw_plan stays planning-disabled.""" +from __future__ import annotations + +import base64 +import json +import os +import sys +import time +import urllib.error +import urllib.request +from datetime import datetime +from pathlib import Path + +BASE = os.environ.get("BASE_URL", "http://127.0.0.1:8080").rstrip("/") +ASSETS = Path(__file__).resolve().parent +ASSETS.mkdir(parents=True, exist_ok=True) +DATE = datetime.now().strftime("%Y%m%d-%H%M%S") +PROJ_NAME = f"rdev-p3-{DATE}" +TASK_TIMEOUT = int(os.environ.get("TASK_TIMEOUT_SEC", "2400")) +LOG: list[str] = [] + + +def log(msg: str) -> None: + line = f"[{datetime.now().strftime('%H:%M:%S')}] {msg}" + print(line, flush=True) + LOG.append(line) + + +def b64(text: str) -> str: + return base64.b64encode(text.encode()).decode("ascii") + + +def req(method, path, token=None, body=None, timeout=60): + data = None + headers = {"Accept": "application/json"} + if body is not None: + data = json.dumps(body, ensure_ascii=False).encode() + headers["Content-Type"] = "application/json" + if token: + headers["Authorization"] = f"Bearer {token}" + r = urllib.request.Request(BASE + path, data=data, headers=headers, method=method) + try: + with urllib.request.urlopen(r, timeout=timeout) as resp: + raw = resp.read().decode() + parsed = json.loads(raw) if raw.strip() else None + return resp.status, parsed, raw + except urllib.error.HTTPError as e: + raw = e.read().decode() + try: + parsed = json.loads(raw) if raw.strip() else None + except json.JSONDecodeError: + parsed = None + return e.code, parsed, raw + + +def save_json(name, obj): + (ASSETS / name).write_text(json.dumps(obj, ensure_ascii=False, indent=2), encoding="utf-8") + + +def login(user, password): + st, parsed, raw = req("POST", "/api/v1/auth/login", body={"username": user, "password": password}) + if st >= 400 or not parsed or not parsed.get("token"): + raise SystemExit(f"login failed: {st} {raw[:300]}") + return parsed["token"], parsed.get("user") or {} + + +def enable_only(plan, keep, author, reviewer, approver): + for stage in plan.get("stages") or []: + for dt in stage.get("doc_tasks") or []: + key = dt.get("task_key") or dt.get("key") + if key in keep: + dt["enabled"] = True + dt["duties"] = { + "author_user_id": author, + "reviewer_user_id": reviewer, + "approver_user_id": approver, + } + else: + dt["enabled"] = False + dt["duties"] = {} + + +def plan_and_activate(token, project_id, workflow_key, keep_keys, author, reviewer, approver): + st, proj, raw = req("GET", f"/api/v1/projects/{project_id}", token) + if st != 200: + raise SystemExit(f"get project: {st} {raw[:400]}") + sel_ver = int(proj.get("workflow_selection_version") or 1) + plan_rev = int(proj.get("workflow_plan_revision") or 0) + st, plan, raw = req( + "GET", + f"/api/v1/projects/{project_id}/workflow-plan/default?workflow_key={workflow_key}&version=0", + token, + ) + if st != 200: + raise SystemExit(f"default plan: {st} {raw[:800]}") + keys = [] + for stage in plan.get("stages") or []: + for dt in stage.get("doc_tasks") or []: + keys.append(dt.get("task_key") or dt.get("key")) + log(f"{workflow_key} task keys={keys}") + enable_only(plan, set(keep_keys), author, reviewer, approver) + st, _, raw = req("PUT", f"/api/v1/projects/{project_id}/workflow-plan", token, { + "plan": plan, + "expected_plan_revision": plan_rev, + "expected_selection_version": sel_ver, + }) + log(f"save {workflow_key} plan http={st}") + if st != 200: + raise SystemExit(raw[:1200]) + st, preview, raw = req("POST", f"/api/v1/projects/{project_id}/activation-preview", token) + if st != 200: + raise SystemExit(f"preview: {st} {raw[:800]}") + st, activated, raw = req("POST", f"/api/v1/projects/{project_id}/workflow-instances/activate", token, { + "confirmation_token": preview["confirmation_token"], + "expected_project_version": preview["expected_project_version"], + "expected_plan_revision": preview["expected_plan_revision"], + }) + log(f"activate {workflow_key} http={st}") + if st != 200: + raise SystemExit(raw[:1200]) + save_json(f"activate-{workflow_key}.json", activated) + return activated + + +def run_task(token, project_id, task_key, fields, author, reviewer, approver, backend="pi-agent", materials=None): + sess = f"sess-s1c-p{project_id}-{task_key}-{int(time.time())}" + req("POST", "/api/v1/chat/sessions", token, { + "session_id": sess, "title": f"{PROJ_NAME}/{task_key}", + "user_id": author, "project_id": project_id, + }) + body = { + "session_id": sess, + "client_turn_id": f"s1c-{task_key}-{int(time.time())}", + "user_message": f"请编制《{task_key}》,严格按模板专业章节写满四段式,不做疗效宣称,缺项标待确认。", + "task_key": task_key, + "project_name": PROJ_NAME, + "customer_name": fields["customer_name"], + "device_type": fields["device_type"], + "intended_use": fields["intended_use"], + "target_market": fields["target_market"], + "fields": fields, + "backend": backend, + "project_id": project_id, + "author_id": author, + "reviewer_id": reviewer, + "approver_id": approver, + "materials": materials or [{"filename": "brief.md", "content": b64("# brief\n无创神经刺激器。\n")}], + } + log(f"start {task_key} backend={backend}") + st, created, raw = req("POST", "/api/v1/tasks/runs", token, body, timeout=60) + if st not in (200, 202) or not created or not created.get("run_id"): + raise SystemExit(f"create run {task_key}: {st} {raw[:1000]}") + run_id = created["run_id"] + t0 = time.time() + final = None + while time.time() - t0 < TASK_TIMEOUT: + gs, gb, _ = req("GET", f"/api/v1/tasks/runs/{run_id}", token, timeout=30) + if gs == 200 and isinstance(gb, dict): + status = gb.get("status") or gb.get("Status") + if status in ("completed", "failed", "cancelled", "pending_author_confirmation", "quality_failed", "finalizing_failed"): + final = gb + log(f"done {task_key} status={status} elapsed={int(time.time()-t0)}s") + break + if int(time.time() - t0) % 30 < 12: + log(f"poll {task_key} status={status} elapsed={int(time.time()-t0)}s") + time.sleep(10) + if not final: + raise SystemExit(f"timeout {task_key} run_id={run_id}") + save_json(f"pi-{task_key}-meta.json", {"run_id": run_id, "final": final, "elapsed_s": int(time.time()-t0)}) + return final + + +def extract_md(final: dict) -> str: + md = "" + work = final.get("WorkspaceID") or final.get("work_dir") or final.get("workspace_id") or "" + roots = [] + if work: + roots.append(Path(work)) + roots.append(Path(work.replace("/app/data/", "/home/weichen/projects/Agent-System/data/dev/"))) + for root in roots: + if not root.exists(): + continue + for p in [root / "output.md", *sorted(root.rglob("output.md"))]: + if p.is_file(): + text = p.read_text(encoding="utf-8") + if len(text) > len(md): + md = text + pa = final.get("primary_artifact") or {} + if len(pa.get("markdown_body") or "") > len(md): + md = pa["markdown_body"] + return md + + +def approve_doc(author_token, reviewer_token, approver_token, doc_id, author_id, reviewer_id, approver_id): + steps = [ + (author_token, "/api/v1/docgov/claim", {"doc_id": doc_id, "user_id": author_id, "user_name": "admin", "user_role": "author"}), + (author_token, "/api/v1/docgov/submit-review", {"doc_id": doc_id, "user_id": author_id, "user_name": "admin"}), + (reviewer_token, "/api/v1/docgov/review-decision", {"doc_id": doc_id, "user_id": reviewer_id, "user_name": "lizhuguan", "action": "approve", "comment": "s1c"}), + (approver_token, "/api/v1/docgov/approver-decision", {"doc_id": doc_id, "user_id": approver_id, "user_name": "wangzong", "action": "approve", "comment": "s1c"}), + ] + for tok, path, body in steps: + st, _, raw = req("POST", path, tok, body) + log(f"{path.split('/')[-1]} http={st}") + if st != 200: + raise SystemExit(f"{path} http={st} {raw[:400]}") + + +def advance_until(token, instance_id, stop_stage: str, plan_stages: list[str]): + for sk in plan_stages: + if sk == stop_stage: + break + st, detail, raw = req("GET", f"/api/v1/workflow-instances/{instance_id}", token) + inst = (detail or {}).get("instance") or detail or {} + rev = inst.get("config_revision") + st, _, raw = req("POST", f"/api/v1/workflow-instances/{instance_id}/stages/{sk}/advance", token, { + "stage_key": sk, "expected_config_revision": rev, + }) + log(f"advance {sk} http={st}") + if st != 200: + raise SystemExit(f"advance {sk} http={st} {raw[:400]}") + + +def main(): + admin_pass = os.environ["ADMIN_PASSWORD"] + token, admin = login(os.environ.get("ADMIN_USERNAME", "admin"), admin_pass) + uid = int(admin["id"]) + # Cross-user duties (seeded) + _, rev_user = login("lizhuguan", "123456") + _, app_user = login("wangzong", "123456") + reviewer_id = int(rev_user["id"]) + approver_id = int(app_user["id"]) + reviewer_token, _ = login("lizhuguan", "123456") + approver_token, _ = login("wangzong", "123456") + fields = { + "customer_name": "水木东方测试客户", + "device_type": "二类有源医疗器械(神经刺激)", + "intended_use": "无创神经电刺激辅助改善目标症状", + "target_market": "中国 NMPA", + } + + # create project + st, proj, raw = req("POST", "/api/v1/projects", token, { + "name": PROJ_NAME, + "product_domain": "medical_device", + "description": "P3 real PI three-sample", + }) + if st not in (200, 201) or not proj: + raise SystemExit(f"create project: {st} {raw[:800]}") + pid = int(proj["id"]) + log(f"project_id={pid}") + save_json("project.json", proj) + + for mid, role in ((uid, "owner"), (reviewer_id, "member"), (approver_id, "member")): + st, _, raw = req("POST", f"/api/v1/projects/{pid}/members", token, {"user_id": mid, "role": role}) + log(f"member user={mid} role={role} http={st}") + + # main: intake only + stub + act = plan_and_activate(token, pid, "main", ["bd_intake"], uid, reviewer_id, approver_id) + inst = act.get("instance") or act + main_iid = int(inst["id"]) + final = run_task(token, pid, "bd_intake", fields, uid, reviewer_id, approver_id, backend="stub") + doc = (final.get("doc_record") or {}) + doc_id = doc.get("doc_id") or f"doc_proj{pid}_bd_intake" + approve_doc(token, reviewer_token, approver_token, doc_id, uid, reviewer_id, approver_id) + # advance main to completed if needed + st, detail, _ = req("GET", f"/api/v1/workflow-instances/{main_iid}", token) + inst = (detail or {}).get("instance") or detail or {} + log(f"main instance status={inst.get('status')}") + + # Try complete remaining main stages + stages = [] + for s in ((act.get("instance") or act).get("config_snapshot") or {}).get("stages") or []: + sk = s.get("stage_key") or s.get("key") + if sk: + stages.append(sk) + if not stages: + # fetch from default was saved earlier; advance generic + stages = ["V0.1_triage", "V0.5_feasibility", "V1_quote"] + advance_until(token, main_iid, "__DONE__", stages) + st, detail, _ = req("GET", f"/api/v1/workflow-instances/{main_iid}", token) + inst = (detail or {}).get("instance") or detail or {} + log(f"main after advance status={inst.get('status')}") + if inst.get("status") != "completed": + raise SystemExit(f"main workflow must complete before rdev, status={inst.get('status')}") + + keep = ["rd_proposal", "rd_planning_review"] + act_r = plan_and_activate(token, pid, "rdev", keep, uid, reviewer_id, approver_id) + rinst = act_r.get("instance") or act_r + rid = int(rinst["id"]) + rstages = [] + for s in (rinst.get("config_snapshot") or {}).get("stages") or []: + sk = s.get("stage_key") + if sk: + rstages.append(sk) + save_json("rdev-stages.json", rstages) + + def enabled_of(key: str): + for s in (rinst.get("config_snapshot") or {}).get("stages") or []: + for dt in s.get("doc_tasks") or []: + k = dt.get("task_key") or dt.get("key") + if k == key: + return bool(dt.get("enabled")) + return None + + proposal_on = enabled_of("rd_proposal") + review_on = enabled_of("rd_planning_review") + sw_on = enabled_of("rd_sw_plan") + log(f"plan flags proposal={proposal_on} review={review_on} sw_plan={sw_on}") + if sw_on is not False: + raise SystemExit(f"rd_sw_plan must stay disabled for planning N/A, got {sw_on}") + if proposal_on is not True or review_on is not True: + raise SystemExit(f"sample tasks must be enabled: proposal={proposal_on} review={review_on}") + + materials_prop = [{"filename": "proposal_brief.md", "content": b64( + "# 立项输入\n\n产品:无创神经电刺激器。\n用途:辅助改善目标症状,不做疗效宣称。\n市场:中国 NMPA 二类有源。\n软件:本项目不含独立软件子系统,软件开发计划在规划期关闭。\n" + )}] + materials_rev = [{"filename": "plan_brief.md", "content": b64( + "# 策划评审输入\n\n项目建议书已起草。\n关键风险:适应症边界待确认;电气安全摸底待排期。\n软件类文件已在规划期关闭,不进入编制。\n" + )}] + + fin1 = run_task(token, pid, "rd_proposal", fields, uid, reviewer_id, approver_id, backend="pi-agent", materials=materials_prop) + md1 = extract_md(fin1) + (ASSETS / "rd_proposal-final.md").write_text(md1, encoding="utf-8") + log(f"proposal chars={len(md1)} placeholder={'按本阶段专业结构写' in md1}") + approve_doc(token, reviewer_token, approver_token, f"doc_proj{pid}_rd_proposal", uid, reviewer_id, approver_id) + + advance_until(token, rid, "RD02_planning_review", rstages) + fin2 = run_task(token, pid, "rd_planning_review", fields, uid, reviewer_id, approver_id, backend="pi-agent", materials=materials_rev) + md2 = extract_md(fin2) + (ASSETS / "rd_planning_review-final.md").write_text(md2, encoding="utf-8") + log(f"planning_review chars={len(md2)} placeholder={'按本阶段专业结构写' in md2}") + + summary = { + "project_id": pid, + "project_name": PROJ_NAME, + "rd_sw_plan_na": {"enabled": sw_on, "close": "planning_disable"}, + "rd_proposal": { + "run_status": fin1.get("status") or fin1.get("Status"), + "chars": len(md1), + "no_placeholder": "按本阶段专业结构写" not in md1, + "has_document_sections": all(h in md1 for h in ("## 项目背景与立项依据", "## 产品定义与范围", "## 主要风险与对策概览")), + }, + "rd_planning_review": { + "run_status": fin2.get("status") or fin2.get("Status"), + "chars": len(md2), + "no_placeholder": "按本阶段专业结构写" not in md2, + "has_review_sections": all(h in md2 for h in ("## 评审范围与对象", "## 问题与决议", "## 评审结论")), + }, + } + save_json("summary-p3.json", summary) + (ASSETS / "console.log").write_text("\n".join(LOG) + "\n", encoding="utf-8") + print(json.dumps(summary, ensure_ascii=False, indent=2)) + ok = ( + summary["rd_sw_plan_na"]["enabled"] is False + and summary["rd_proposal"]["no_placeholder"] + and summary["rd_planning_review"]["no_placeholder"] + and summary["rd_proposal"]["has_document_sections"] + and summary["rd_planning_review"]["has_review_sections"] + and summary["rd_proposal"]["chars"] > 400 + and summary["rd_planning_review"]["chars"] > 400 + and summary["rd_proposal"]["run_status"] in ("completed", "pending_author_confirmation") + and summary["rd_planning_review"]["run_status"] in ("completed", "pending_author_confirmation") + ) + sys.exit(0 if ok else 2) + + +def resume_planning_review(): + """Continue project 6533: approve rd_proposal, then real-PI rd_planning_review.""" + pid = int(os.environ.get("P3_PROJECT_ID", "6533")) + rid = int(os.environ.get("P3_INSTANCE_ID", "361")) + admin_pass = os.environ["ADMIN_PASSWORD"] + token, admin = login(os.environ.get("ADMIN_USERNAME", "admin"), admin_pass) + uid = int(admin["id"]) + _, rev_user = login("lizhuguan", "123456") + _, app_user = login("wangzong", "123456") + reviewer_id = int(rev_user["id"]) + approver_id = int(app_user["id"]) + reviewer_token, _ = login("lizhuguan", "123456") + approver_token, _ = login("wangzong", "123456") + fields = { + "customer_name": "水木东方测试客户", + "device_type": "二类有源医疗器械(神经刺激)", + "intended_use": "无创神经电刺激辅助改善目标症状", + "target_market": "中国 NMPA", + } + approve_doc(token, reviewer_token, approver_token, f"doc_proj{pid}_rd_proposal", uid, reviewer_id, approver_id) + rstages = json.loads((ASSETS / "rdev-stages.json").read_text(encoding="utf-8")) + advance_until(token, rid, "RD02_planning_review", rstages) + materials_rev = [{"filename": "plan_brief.md", "content": b64( + "# 策划评审输入\n\n项目建议书已起草。\n关键风险:适应症边界待确认;电气安全摸底待排期。\n软件类文件已在规划期关闭,不进入编制。\n" + )}] + fin2 = run_task(token, pid, "rd_planning_review", fields, uid, reviewer_id, approver_id, backend="pi-agent", materials=materials_rev) + md2 = extract_md(fin2) + (ASSETS / "rd_planning_review-final.md").write_text(md2, encoding="utf-8") + log(f"planning_review chars={len(md2)} placeholder={'按本阶段专业结构写' in md2}") + md1 = (ASSETS / "rd_proposal-final.md").read_text(encoding="utf-8") + summary = { + "project_id": pid, + "resumed": True, + "rd_sw_plan_na": {"enabled": False, "close": "planning_disable"}, + "rd_proposal": { + "run_status": "completed", + "chars": len(md1), + "no_placeholder": "按本阶段专业结构写" not in md1, + "template_headings": all(h in md1 for h in ("## 项目背景与立项依据", "## 产品定义与范围", "## 主要风险与对策概览")), + }, + "rd_planning_review": { + "run_status": fin2.get("status") or fin2.get("Status"), + "chars": len(md2), + "no_placeholder": "按本阶段专业结构写" not in md2, + "has_review_sections": all(h in md2 for h in ("## 评审范围与对象", "## 问题与决议", "## 评审结论")), + }, + } + save_json("summary-p3.json", summary) + (ASSETS / "console.log").write_text("\n".join(LOG) + "\n", encoding="utf-8") + print(json.dumps(summary, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + if os.environ.get("P3_RESUME") == "review": + resume_planning_review() + else: + main() diff --git a/.doc/test-reports/assets/2026-09-19-rdev-p3-real-pi/summary-p3.json b/.doc/test-reports/assets/2026-09-19-rdev-p3-real-pi/summary-p3.json new file mode 100644 index 00000000..594f4a25 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-19-rdev-p3-real-pi/summary-p3.json @@ -0,0 +1,27 @@ +{ + "project_id": 6533, + "backend": "pi-agent", + "model": "MiniMax-M2.7-highspeed", + "rd_sw_plan_na": { + "enabled": false, + "close": "planning_disable" + }, + "rd_proposal": { + "run_status": "completed", + "elapsed_s": 430, + "chars": 11550, + "no_placeholder": true, + "template_headings": false + }, + "rd_planning_review": { + "run_status": "quality_failed", + "elapsed_s": 580, + "chars": 13225, + "no_placeholder": true, + "has_review_sections": true, + "quality_score": 20, + "violations": [ + "问题行缺少问题、决议、责任人或期限" + ] + } +}