diff --git a/.doc/archive/ops/2026-09-17-rdev-template-depth.md b/.doc/archive/ops/2026-09-17-rdev-template-depth.md new file mode 100644 index 00000000..90b06db2 --- /dev/null +++ b/.doc/archive/ops/2026-09-17-rdev-template-depth.md @@ -0,0 +1,54 @@ +--- +title: "rdev 模板深度补强 S0 + S1 首批" +status: done +created: 2026-09-17 +updated: 2026-09-17 +owner: Cursor +branch: feature/rdev-template-depth +worktree: ".worktrees/feature-rdev-template-depth" +mutex: rdev-templates +--- + +# rdev 模板深度补强 S0 + S1 首批 + +## 目标 + +修复 rdev leader prompt 错配,并为阶段 01–05 的 14 份 rdev 模板补齐 ISO 13485 专业章节与逐节写作指令,以 dev 真实 PI 打样验证收口。 + +## 范围 + +- S0.1 B1:`rdev_leader.md` + InstructionsFile 注入链 +- S0.2:`rd_design_input_spec` 样例 + 写作规范 + lint +- S0.3:dev 真实 PI 打样 +- S1 首批:阶段 01–05 共 14 份模板(分 3 批) + +## 非目标 + +- overlay 机制本体、R1–R7 二期、per-stage 步骤定制、模型配置化、manifest 元数据、前端(P2)、键名空间化(P4)、阶段 06–13 模板 + +## 步骤 + +1. [x] S0.1 leader prompt 注入链(`6a09062`) +2. [x] S0.2 样例模板 + 规范 + lint(含于 `eb09b21`) +3. [x] S0.3 真实 PI 打样(项目 6424 intake + 6425 `rd_design_input_spec`) +4. [x] S1 批 1–3(`eb09b21`) +5. [x] 文档与门禁 + +## 验收标准 + +- [x] rdev leader AGENTS.md 含「设计控制」且不含「商务对接负责人」「CDO」 +- [x] intake leader 回归仍含「商务对接负责人」 +- [x] 14 份模板 lint 绿灯;真 PI 终稿五节实质论证 +- [x] `go vet` + `go test -short` 全绿 + +## 相关链接 + +- Test report: [.doc/test-reports/2026-09-17-rdev-template-depth-test-report.md](../../test-reports/2026-09-17-rdev-template-depth-test-report.md) +- Assets: [.doc/test-reports/assets/2026-09-17-rdev-template-depth/](../../test-reports/assets/2026-09-17-rdev-template-depth/) +- Backlog: [.doc/backlog/2026-09-17-rdev-phase2-backlog.md](../../backlog/2026-09-17-rdev-phase2-backlog.md) +- 写作规范: [.doc/system-design/project-workflow/08-rdev模板写作规范.md](../../system-design/project-workflow/08-rdev模板写作规范.md) + +## 证据 / 备注 + +- 依赖 `feature/rdev-core`(尚未合 dev);合入前需 rebase 丢弃已进 dev 的 engineering-dashboard 重复提交。 +- 真 PI:`run_1789635054471569201`(intake ~220s);`run_1789635960880707641`(DI ~450s,`stage=RD03_design_input`)。 diff --git a/.doc/backlog/2026-09-17-rdev-phase2-backlog.md b/.doc/backlog/2026-09-17-rdev-phase2-backlog.md index c161144e..65c7b661 100644 --- a/.doc/backlog/2026-09-17-rdev-phase2-backlog.md +++ b/.doc/backlog/2026-09-17-rdev-phase2-backlog.md @@ -43,3 +43,28 @@ ## 依赖关系 - R2/R3 可并行;R4 依赖 manifest 落地后的 upstream 声明表;R1 独立;R5/R6/R7 低优先级。 + +--- + +## 模板深度与运行时续批(S1 续批 / S2 / S3) + +> 来源:Kimi 分析方案 + [2026-09-17-rdev-template-depth](../archive/ops/2026-09-17-rdev-template-depth.md) 收口。S0 + S1 首批(14 份)已交付;以下不阻塞本轮合并候选。 + +### S1 续批 — 剩余模板专业章节 + +- **范围**:阶段 06–13 尚未补强的约 27 份通用占位模板 + 中等档约 9 份(补逐节指令与预填行);评审记录类已较完整者可跳过或轻触 +- **方法**:沿用 [08-rdev模板写作规范](../system-design/project-workflow/08-rdev模板写作规范.md);`rdev_template_lint_test` allowlist 随批增长 +- **验收**:lint 绿灯;抽样 1–2 份真 PI 或 stub 结构抽检 + +### S2 — 运行时编排与配置化 + +- per-stage 步骤覆盖(相对默认 organize→engineer→draft→review 的阶段差异) +- regulatory 步接 `complexity_tier`(与 R7 可合并认领) +- 模型去硬编码(配置/环境驱动) +- manifest hint + aliases 元数据补齐 + +### S3 — overlay 与质量门禁扩面 + +- 轻量 overlay 机制(模板管结构;overlay/运行时管纪律与粒度下限) +- R2/R3 专用确定性门禁落地 +- P3:三样本真 PI E2E 报告 + CI 四工作流门禁挂钩 diff --git a/.doc/ops/CURRENT.md b/.doc/ops/CURRENT.md index 2b5d9086..78d89b1c 100644 --- a/.doc/ops/CURRENT.md +++ b/.doc/ops/CURRENT.md @@ -14,6 +14,7 @@ | owner | task | branch | worktree | mutex | status | |-------|------|--------|----------|-------|--------| | Cursor | 2026-09-17-rdev-workflow-integration | feature/rdev-core | - | workflow-def | in_progress | +| Cursor | 2026-09-17-rdev-template-depth | feature/rdev-template-depth | .worktrees/feature-rdev-template-depth | rdev-templates | done | | Cursor | 2026-09-17-initial-load-perf-u2 | feature/initial-load-perf-u2 | - | web + static-delivery | done | | Codex | 2026-09-17-initial-load-performance-plan | feature/initial-load-performance-plan | .worktrees/feature-initial-load-performance-plan | loading-performance-audit | done | | Kimi | 2026-09-17-system-admin-console | feature/system-admin-console | - | web + sysadmin | done | diff --git a/.doc/status/FEATURE-MATRIX.md b/.doc/status/FEATURE-MATRIX.md index a1dcbc59..42c320e8 100644 --- a/.doc/status/FEATURE-MATRIX.md +++ b/.doc/status/FEATURE-MATRIX.md @@ -55,7 +55,7 @@ | 对话数据治理(D7) | 留存/删除口径、库·备份·日志控制、敏感字段加密边界 | deferred | deferred_enhancement(违规则升 blocker) | [计划](../remediation/2026-09-16-feature-matrix-production-readiness-plan.md) Scope Boundaries;[收口 §7.1](../remediation/2026-09-16-partial-deferred-completion-plan.md);[D7 ADR 草案](../adr/2026-09-17-d7-chat-data-retention.md);[W7 盘点](../audit/2026-09-17-d7-data-inventory.md);[报告](../test-reports/2026-09-17-w7-d7-inventory-test-report.md) | **after W7**:只读盘点完成(sessions/messages/KB/日志/备份/event)。**未发现**已确认基线违规,未写 gap-matrix。口径仍 `pending-compliance-signoff`;禁止按 365/180/30 物理删除。本行不升 done | `chat` | | 智能体小队 | 角色-任务-工作区-黑板 | done | non_blocker | [agent-squad](../system-design/agent-squad/);[test 2026-09-07](../test-reports/2026-09-07-dynamic-squad-planning-test-report.md) | 非关键步骤降级(A5/A6)属 backlog | `squad` | | 工作流治理 | 三正式工作流、设置页/DutyMode、动作级鉴权、真实 PI 三工作流 E2E、full/none 混合长链 | done | non_blocker | [三工作流整改](../remediation/2026-09-12-three-workflows-strict-governance-remediation.md);[409/职责](../test-reports/2026-09-14-workflow-plan-409-frozen-and-optional-duties-test-report.md);[鉴权](../test-reports/2026-09-14-governance-action-level-authz-test-report.md);[PI E2E](../test-reports/2026-09-16-pi-three-workflow-e2e-test-report.md);[Wave2 full/none](../test-reports/2026-09-16-wave2-real-pi-evidence-test-report.md) | full 跨用户审批 + none 免审批不阻塞已签。纯软件自举仍独立 planned | `workflow` | -| 研发设计控制(rdev) | 医疗第 4 工作流:13×60 manifest/模板、`squad.rdev_doc.v1` kind 编排、main-completed 硬 precheck、StageKey 动态化;不含前端/真 PI/键名空间化 | partial | deferred_enhancement | [设计](../system-design/project-workflow/07-研发工作流rdev接入-设计与实施计划.md);[short-term](../ops/short-term/2026-09-17-rdev-workflow-integration.md);[backlog R1–R7](../backlog/2026-09-17-rdev-phase2-backlog.md) | **P0+P1 done**(齐套/precheck/stub)。关闭条件:P2 前端治理 + P3 真 PI 三样本报告 + CI 四工作流门禁。P4 键名空间化独立行/任务 | `workflow-def` | +| 研发设计控制(rdev) | 医疗第 4 工作流:13×60 manifest/模板、`squad.rdev_doc.v1` kind 编排、main-completed 硬 precheck、StageKey 动态化;不含前端/真 PI/键名空间化 | partial | deferred_enhancement | [设计](../system-design/project-workflow/07-研发工作流rdev接入-设计与实施计划.md);[short-term](../ops/short-term/2026-09-17-rdev-workflow-integration.md);[模板深度](../archive/ops/2026-09-17-rdev-template-depth.md);[模板深度报告](../test-reports/2026-09-17-rdev-template-depth-test-report.md);[写作规范](../system-design/project-workflow/08-rdev模板写作规范.md);[backlog](../backlog/2026-09-17-rdev-phase2-backlog.md) | **P0+P1 done**。**模板深度 S0+S1 首批 done**:leader prompt 已修(`rdev_leader` + InstructionsFile 注入);14/60 模板已补强(阶段 01–05);真 PI 打样 PASS(项目 6424 intake + 6425 `rd_design_input_spec`,`stage=RD03_design_input`)。剩余:27 份模板 + 中等档补强(S1 续批)、S2/S3、P2 前端、P3 三样本 E2E、P4 键名空间化 | `workflow-def` / `rdev-templates` | | 纯软件项目自举 | 软件项目创建、Bootstrap、Delivery、受控工程交接 | partial | deferred_enhancement(明确不挡首发) | [设计](../system-design/2026-09-14-software-project-bootstrap-workflow.md);[ADR](../adr/2026-09-16-software-project-bootstrap-keys.md);[L1 报告](../test-reports/2026-09-16-software-project-bootstrap-test-report.md);[W5a](../test-reports/2026-09-17-w5a-software-bootstrap-ui-pi-test-report.md) | **before**:L1 + UI 仍克隆医疗模板。**after W5a**:catalog 驱动创建、软件不挂医疗 key、docs_only 真 PI 建议 delivery 且不自动激活。**SWBOOT-10 仍 stub**(W5b);本行不升 done | `workflow-design` | | IAM / 鉴权 | 项目级 API 鉴权 + RBAC;会话/阶段授权 | done | 加固 | [v3 full inventory](../audit/authorization-matrix-v3-full.md);[session 中断](../test-reports/2026-09-16-iam-route-inventory-test-report.md);[fail-closed](../test-reports/2026-09-16-wave1-iam-fail-closed-test-report.md);[410 策略](../audit/2026-09-16-bug11-410-retire-decision.md);[R13](../audit/2026-09-16-r13-data-safety-checklist.md) | 全路由 inventory + session 中断负例 + 410 冻结 + R13 基线已签 | `authz` | | 文档治理 | 法定文档生命周期 + 租约 + 受控正文读取 | done | non_blocker | [docgov](../test-reports/2026-09-08-docgov-lifecycle-and-claiming-framework-test-report.md);[正文 UI](../test-reports/2026-09-14-controlled-content-ui-acceptance.md);[canonical hash](../remediation/2026-09-14-controlled-content-canonical-hash-remediation.md) | 项目 143 只读;不终止 | `docgov` | diff --git a/.doc/system-design/module-boundaries.yaml b/.doc/system-design/module-boundaries.yaml index 9fba27c8..f43a0709 100644 --- a/.doc/system-design/module-boundaries.yaml +++ b/.doc/system-design/module-boundaries.yaml @@ -248,6 +248,7 @@ imports: - app/uow sysadmin: - config + engineeringdashboard: [] table_owners: document_records: diff --git a/.doc/system-design/project-workflow/08-rdev模板写作规范.md b/.doc/system-design/project-workflow/08-rdev模板写作规范.md new file mode 100644 index 00000000..77808bb1 --- /dev/null +++ b/.doc/system-design/project-workflow/08-rdev模板写作规范.md @@ -0,0 +1,54 @@ +# rdev 模板写作规范 + +> 适用范围:`templates/docs/rd_*.md`(研发设计控制 / ISO 13485 DHF) +> 更新日期:2026-09-17 + +## 1. 分工红线(强制) + +| 层 | 负责 | 不负责 | +| --- | --- | --- | +| **模板**(`templates/docs/rd_*.md`) | 章节结构、表头、逐节写作指令、示例「待确认」行、治理骨架(编号/适用性/追溯/签署) | 运行时角色口吻、模型选择、粒度下限的强制执行 | +| **overlay / 运行时**(`configs/agents/*`、`configs/shared/writing.md`、未来 overlays) | 写作纪律、DHF 粒度下限、禁止编造、角色边界 | 替代模板定义专业章节结构 | + +一句话:**模板管结构与占位;overlay/运行时管写作纪律与粒度下限。** + +## 2. 八条基准(源自商务模板实践) + +1. **结论先行**:文首结论句完整;后文不得与结论打架。 +2. **四段式展开**:结论句 → 表格或列表 → 解读段落 → 出处/支撑;禁止通篇只有列表。 +3. **括号指令可执行**:每节括号内写清覆盖范围、缺项规则、禁止项;禁止只写「按本阶段专业结构写」。 +4. **表不交空壳**:至少一行「待确认」示例行;禁止空表头。 +5. **缺项显式**:统一标「待确认」,并在「待确认清单」汇总。 +6. **不做疗效宣称**:设计控制文档禁止疗效/临床效果绝对化用语。 +7. **禁止残留提示**:终稿不得留下括号写作提示原文。 +8. **追溯可填**:`| RD-` 行存在;上游/下游未知写「待确认」不留空白无说明。 + +## 3. 治理骨架(每份 rd_ 模板保留) + +- 文首元数据:项目 / 生成时间 / 快照 / 文件编号 / 记录归属:DHF / 版本 / 阶段 +- `## 结论` / `## 适用性` +- 专业正文各节(≥4 个 `## ` 专业或治理章节合计满足 lint) +- `## 追溯`(含 `| RD-` 行) +- `## 已有材料摘要` / `## 待确认清单` / `## 签署` / `## 说明` + +## 4. 补强清单与批次 + +| 批次 | 范围 | 状态 | +| --- | --- | --- | +| S0 样例 | `rd_design_input_spec` | 本轮 | +| S1 批 1 | `rd_proposal` / `rd_design_input_list` / `rd_system_design` / `rd_regs_stds` / `rd_adverse_events` | 本轮 | +| S1 批 2 | `rd_sw_plan` / `rd_sw_reqs` / `rd_sw_config` / `rd_risk_plan` | 本轮 | +| S1 批 3 | `rd_design_plan` / `rd_user_needs` / `rd_hazard_analysis` / `rd_system_reqs`(SRS 深度移植) | 本轮 | +| S1 续批 | 阶段 06–13 剩余约 27 份 + 中等档约 9 份 | follow-up | +| S2 / S3 | per-stage 步骤、overlay 机制、专用门禁 | follow-up | + +## 5. Lint 门禁 + +`internal/workflowdef/rdev_template_lint_test.go` 对「已补强 allowlist」断言: + +- 不含「按本阶段专业结构写」 +- 正文 `## ` 章节 ≥ 4 +- 含追溯表行 `| RD-` +- 含 `## 待确认清单` 与 `## 签署` + +未列入 allowlist 的模板不参与断言;随批次增长扩大 allowlist。 diff --git a/.doc/test-reports/2026-09-17-rdev-template-depth-test-report.md b/.doc/test-reports/2026-09-17-rdev-template-depth-test-report.md new file mode 100644 index 00000000..f482081a --- /dev/null +++ b/.doc/test-reports/2026-09-17-rdev-template-depth-test-report.md @@ -0,0 +1,118 @@ +# rdev 模板深度补强(S0 + S1 首批)测试报告 + +## 一、 测试背景 (Background) + +`rdev` 60 份模板多数仍含「按本阶段专业结构写」通用占位;且 `rdevLeaderAgent` 虽注册了角色,但 `buildSubWorkspaces` 按角色名加载 `configs/agents/leader.md`,导致研发终审全部回落商务口吻。本轮按计划交付 B1 leader 注入修复、阶段 01–05 共 14 份模板专业章节补强,并以 dev 真实 PI 打样收口。 + +## 二、 测试目标 (Test Objectives) + +- rdev leader 子工作区 `AGENTS.md` 含「设计控制 / 研发设计控制负责人」,且不含「商务对接负责人」「CDO」 +- intake leader 回归仍含「商务对接负责人」 +- 14 份已补强模板 lint 绿灯(无通用占位、章节≥4、含追溯/待确认/签署) +- 真实 PI:`rd_design_input_spec` 终稿五节有实质论证;账本 `stage=RD03_design_input` +- `go vet ./...` 与 `go test -short` 全绿 + +## 三、 测试方案与环境 (Test Plan & Environment) + +| 项 | 值 | +|---|---| +| OS | Linux | +| 分支 / worktree | `feature/rdev-template-depth` / `.worktrees/feature-rdev-template-depth` | +| 后端 | `pi-agent` + MiniMax(shuimu-pi-agent-dev) | +| HTTP | `http://127.0.0.1:8080`(agent-dev) | +| 层级 | 单元(prompt 注入 / lint)+ 包回归 short + 真 PI 端到端 | + +资产目录:[assets/2026-09-17-rdev-template-depth/](./assets/2026-09-17-rdev-template-depth/) + +## 四、 预期结果 (Expected Results) + +| 用例 | 预期 | +|------|------| +| S0.1 PrepareWorkspace(rd_design_input_spec) | leader AGENTS 设计控制口径,无商务串味 | +| S0.1 PrepareWorkspace(intake) | leader AGENTS 仍含商务对接负责人 | +| S0.2 / S1 lint allowlist 14 份 | 无「按本阶段专业结构写」;`## `≥4;含 `\| RD-`、待确认、签署 | +| S0.3 main-only intake | 真 PI completed;文档 `stage=V0.1_triage`;实例 completed | +| S0.3 rdev-only DI | 真 PI completed;五节实质;`stage=RD03_design_input`;leader 无商务串味 | + +## 五、 实际测试结果与判定 (Actual Results & Evaluation) + +### 5.1 S0.1 leader prompt 注入(单元) + +- **测试输入**: `go test -short ./internal/squad/ -run 'RDevLeader|LeaderPrompt|InstructionsFile' -count=1`(及全包 short) +- **实际输出**: `ok chat-agent-system/internal/squad`(见第六节汇总) +- **判定**: PASS — `GetAgentInstructionFile` + `InstructionsFile` 优先注入已覆盖;商务回归保留 + +### 5.2 模板 lint(S0.2 + S1 14 份) + +- **测试输入**: `go test -short ./internal/workflowdef/ -run RDevTemplateLint -count=1` +- **判定**: PASS — allowlist 覆盖 `rd_design_input_spec` + 批 1/2/3 共 14 份 + +### 5.3 真实 PI:main 仅 intake(项目 6424) + +- **测试输入**: 新建 medical_device 项目;规划期仅保留 `intake`;`backend=pi-agent`;异步 `POST /api/v1/tasks/runs` +- **实际输出**(摘自 [pi-intake-meta.json](./assets/2026-09-17-rdev-template-depth/pi-intake-meta.json)): + +```text +run_id=run_1789635054471569201 +Status=completed +WorkflowStageKey=V0.1_triage +WorkspaceID=/app/data/workspaces/bizdev/intake_1789635054485631143 +duration_ms=220109 +``` + +- 终稿取样:[intake-final.md](./assets/2026-09-17-rdev-template-depth/intake-final.md) +- intake leader(商务回归):[intake-leader-AGENTS.md](./assets/2026-09-17-rdev-template-depth/intake-leader-AGENTS.md) 含「商务对接负责人」 +- 实例推进至 completed:[main-instance-final.json](./assets/2026-09-17-rdev-template-depth/main-instance-final.json) +- **判定**: PASS +- **耗时**: ~220 s + +### 5.4 真实 PI:rdev 仅 rd_design_input_spec(项目 6425) + +- **测试输入**: 激活 `rdev`;规划期仅保留 `rd_design_input_spec`;推进至 RD03;同项目插入 completed `main` 实例以满足硬 precheck;真 PI 生成 +- **实际输出**(摘自 [summary-rdev.json](./assets/2026-09-17-rdev-template-depth/summary-rdev.json) / [pi-rd_design_input_spec-meta.json](./assets/2026-09-17-rdev-template-depth/pi-rd_design_input_spec-meta.json)): + +```text +run_id=run_1789635960880707641 +Status=completed +WorkflowStageKey=RD03_design_input +di_chars≈15988 +has_five_sections=true(## 一、功能要求 … ## 五、法规与标准符合性) +no_placeholder=true +agents_ok=true(研发设计控制负责人) +no_business_in_agents=true +no_business_in_final=true +wall≈450s(09:06–09:13Z) +``` + +- 终稿:[rd_design_input_spec-final.md](./assets/2026-09-17-rdev-template-depth/rd_design_input_spec-final.md) +- leader AGENTS:[rdev-leader-AGENTS.md](./assets/2026-09-17-rdev-template-depth/rdev-leader-AGENTS.md) 开篇为「研发/设计控制小队的负责人…不做报价核算与商务承诺」 +- 账本 stage:[rd_design_input_spec-docgov.json](./assets/2026-09-17-rdev-template-depth/rd_design_input_spec-docgov.json) → `"stage":"RD03_design_input"` +- **判定**: PASS(五节均有结论句 + 事实表 + 缺口标注;无通用占位;无商务/CDO 串味) +- **耗时**: ~450 s(小队墙钟);squad 产出约 5 min(organize→review) +- **备注**: 终稿章节标题为「## 一、功能要求」等形式(带中文序号),语义覆盖模板五节。 + +## 六、 自动化测试套件汇总 (Test Suite Execution) + +```text +$ go vet ./... +(无输出,exit 0) + +$ env -u DATA_DIR go test -short ./internal/squad/ ./internal/template/ ./internal/workflowdef/ +ok chat-agent-system/internal/squad 0.030s +ok chat-agent-system/internal/template 0.810s +ok chat-agent-system/internal/workflowdef 0.004s + +$ env -u DATA_DIR go test -short ./... +# 全包 PASS(exit 0;约 59s)。说明:宿主若 export 了 DATA_DIR=./data/dev, +# 会覆盖 bizdev-cli 测试 -env 内的临时目录,导致相对路径读不到 squad.json;门禁以 unset DATA_DIR 为准。 +# 另:本分支自带的 engineeringdashboard 包已补入 module-boundaries.yaml allowlist(随 rebase 丢弃 eng-dashboard 重复提交后可再收敛)。 +``` + +## 七、 测试结论与后续优化建议 (Conclusion & Next Steps) + +- **结论**: S0 + S1 首批达到合并候选标准(代码+真 PI 取样+门禁)。leader 错配已修;14/60 模板已补强。 +- **后续**(见 [backlog](../backlog/2026-09-17-rdev-phase2-backlog.md)): + - S1 续批:阶段 06–13 剩余模板 + 中等档补指令 + - S2:per-stage 步骤 / regulatory×complexity_tier / 模型去硬编码 / manifest hint + - S3:轻量 overlay + R2/R3 门禁 + P3 三样本 E2E +- **合 dev 提示**: 依赖 `feature/rdev-core`;合入前对 rdev-core `rebase dev`,丢弃已进 dev 的 engineering-dashboard 重复提交。 diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/activate-main.json b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/activate-main.json new file mode 100644 index 00000000..39ce031b --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/activate-main.json @@ -0,0 +1,100 @@ +{ + "project_id": 6424, + "lifecycle_status": "active", + "active_workflow_key": "main", + "instance": { + "id": 287, + "project_id": 6424, + "workflow_version_id": 93, + "instance_no": 1, + "status": "active", + "config_revision": 1, + "plan_hash": "fa4721466a102c2cc4dc0d4a454e8ca684982571136b3f068d66fb428a417146", + "config_snapshot": { + "workflow_definition_key": "main", + "workflow_version": 2, + "workflow_version_id": 93, + "stages": [ + { + "stage_key": "V0.1_triage", + "stage_name": "V0.1 需求摸底", + "enabled": true, + "doc_tasks": [ + { + "task_key": "intake", + "task_title": "用户初始需求收集表", + "enabled": true, + "approval_configurable": true, + "duties": { + "author_user_id": 9, + "reviewer_user_id": 11, + "approver_user_id": 12 + } + } + ] + }, + { + "stage_key": "V0.5_feasibility", + "stage_name": "V0.5 方案与可行性", + "enabled": true, + "doc_tasks": [ + { + "task_key": "feasibility_dev", + "task_title": "设计开发可行性评估报告", + "enabled": false, + "approval_configurable": true, + "duties": {} + }, + { + "task_key": "feasibility_reg", + "task_title": "注册路径可行性评估报告", + "enabled": false, + "approval_configurable": true, + "duties": {} + }, + { + "task_key": "prelim_design", + "task_title": "系统初步设计方案", + "enabled": false, + "approval_configurable": true, + "duties": {} + }, + { + "task_key": "research", + "task_title": "调研报告", + "enabled": false, + "approval_configurable": true, + "duties": {} + }, + { + "task_key": "user_requirements", + "task_title": "用户需求表", + "enabled": false, + "approval_configurable": true, + "duties": {} + } + ] + }, + { + "stage_key": "V1.0_quoting", + "stage_name": "V1.0 商务报价", + "enabled": true, + "doc_tasks": [ + { + "task_key": "cdo_quote", + "task_title": "CDO 报价单", + "enabled": false, + "approval_configurable": true, + "duties": {} + } + ] + } + ] + }, + "activated_by": 9, + "activated_at": "2026-09-17T08:50:54.464545Z", + "created_by": 9, + "created_at": "2026-09-17T08:50:54.455933Z", + "updated_at": "2026-09-17T08:50:54.464545Z" + } +} \ No newline at end of file diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/activate-rdev.json b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/activate-rdev.json new file mode 100644 index 00000000..814edd36 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/activate-rdev.json @@ -0,0 +1 @@ +{"project_id":6425,"lifecycle_status":"active","active_workflow_key":"rdev","instance":{"id":291,"project_id":6425,"workflow_version_id":99,"instance_no":1,"status":"active","config_revision":1,"plan_hash":"7aee1fa49614efd069e683476d2cbf5f1b3a7138a7af97ed035bd4941601cbb5","config_snapshot":{"workflow_definition_key":"rdev","workflow_version":2,"workflow_version_id":99,"stages":[{"stage_key":"RD01_planning","stage_name":"01 设计和开发策划","enabled":true,"doc_tasks":[{"task_key":"rd_design_plan","task_title":"设计开发计划任务书","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_proposal","task_title":"项目建议书","enabled":false,"approval_configurable":true,"duties":{}}]},{"stage_key":"RD02_planning_review","stage_name":"02 策划评审","enabled":true,"doc_tasks":[{"task_key":"rd_planning_review","task_title":"设计和开发策划评审记录","enabled":false,"approval_configurable":true,"duties":{}}]},{"stage_key":"RD03_design_input","stage_name":"03 设计输入","enabled":true,"doc_tasks":[{"task_key":"rd_adverse_events","task_title":"同类产品不良事件信息","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_design_input_list","task_title":"设计输入清单","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_design_input_spec","task_title":"设计输入规格书","enabled":true,"approval_configurable":true,"duties":{"author_user_id":9,"reviewer_user_id":11,"approver_user_id":12}},{"task_key":"rd_hazard_analysis","task_title":"安全性问题清单及可能危险分析表","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_regs_stds","task_title":"法规和标准清单","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_risk_plan","task_title":"风险管理计划","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_sw_config","task_title":"软件配置及维护计划","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_sw_plan","task_title":"软件开发计划","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_sw_reqs","task_title":"软件需求规格书","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_system_design","task_title":"系统设计方案","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_system_reqs","task_title":"系统需求规格书","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_user_needs","task_title":"用户需求规格书","enabled":false,"approval_configurable":true,"duties":{}}]},{"stage_key":"RD04_requirements_review","stage_name":"04 需求评审","enabled":true,"doc_tasks":[{"task_key":"rd_req_review","task_title":"需求评审记录","enabled":false,"approval_configurable":true,"duties":{}}]},{"stage_key":"RD05_input_phase_review","stage_name":"05 输入阶段评审","enabled":true,"doc_tasks":[{"task_key":"rd_input_phase_review","task_title":"设计开发评审记录(阶段3和4)","enabled":false,"approval_configurable":true,"duties":{}}]},{"stage_key":"RD06_design_output","stage_name":"06 设计输出","enabled":true,"doc_tasks":[{"task_key":"rd_design_output_list","task_title":"设计输出清单","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_drawings_3d","task_title":"2D图纸和3D模型","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_ee_bom","task_title":"电子电气BOM","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_electrical_sys","task_title":"系统电气设计图","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_fqc","task_title":"成品检验规范","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_ifu","task_title":"产品使用说明书","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_incoming_iqc","task_title":"原材料进货检验规范","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_ipqc","task_title":"生产过程检验规范","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_packaging","task_title":"包装图纸和设计要求","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_pcba","task_title":"PCBA原理图及Layout","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_process_flow","task_title":"工艺流程图及作业指导","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_product_bom","task_title":"产品BOM","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_purchase_spec","task_title":"采购技术规范","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_risk_report","task_title":"风险管理报告","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_sw_arch","task_title":"软件概要设计方案","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_sw_ui","task_title":"软件UI设计文档","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_tech_req","task_title":"产品技术要求","enabled":false,"approval_configurable":true,"duties":{}}]},{"stage_key":"RD07_output_review","stage_name":"07 输出评审","enabled":true,"doc_tasks":[{"task_key":"rd_output_review","task_title":"设计开发评审记录(阶段6)","enabled":false,"approval_configurable":true,"duties":{}}]},{"stage_key":"RD08_verification","stage_name":"08 验证","enabled":true,"doc_tasks":[{"task_key":"rd_biocompatibility","task_title":"生物学检测方案","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_cleaning","task_title":"清洁消毒验证方案","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_design_vv","task_title":"设计验证方案","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_emc_safety","task_title":"EMC及安规摸底报告","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_lifetime","task_title":"产品使用期限研究方案","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_prototype_photos","task_title":"样机照片","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_qualified_suppliers","task_title":"合格供方名录","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_risk_report_v","task_title":"风险管理报告(验证阶段)","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_shelf_life","task_title":"货架寿命方案","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_sw_release","task_title":"软件发布清单","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_sw_sys_test","task_title":"软件系统测试报告","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_sw_unit_test","task_title":"软件单元测试报告","enabled":false,"approval_configurable":true,"duties":{}}]},{"stage_key":"RD09_verification_review","stage_name":"09 验证评审","enabled":true,"doc_tasks":[{"task_key":"rd_verification_review","task_title":"设计开发评审记录(验证阶段)","enabled":false,"approval_configurable":true,"duties":{}}]},{"stage_key":"RD10_transfer","stage_name":"10 转换","enabled":true,"doc_tasks":[{"task_key":"rd_dmr_list","task_title":"DMR文件清单","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_pack_ship","task_title":"包装运输方案","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_risk_report_t","task_title":"风险管理报告(转换阶段)","enabled":false,"approval_configurable":true,"duties":{}}]},{"stage_key":"RD11_transfer_review","stage_name":"11 转换评审","enabled":true,"doc_tasks":[{"task_key":"rd_transfer_review","task_title":"设计开发评审记录(转换阶段)","enabled":false,"approval_configurable":true,"duties":{}}]},{"stage_key":"RD12_validation","stage_name":"12 确认","enabled":true,"doc_tasks":[{"task_key":"rd_animal_study","task_title":"动物试验方案","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_clinical","task_title":"临床试验报告","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_risk_report_val","task_title":"风险管理报告(确认阶段)","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_sw_quality","task_title":"软件质量测试报告","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_use_error","task_title":"使用错误评估报告","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_user_test","task_title":"用户测试报告","enabled":false,"approval_configurable":true,"duties":{}},{"task_key":"rd_validation_plan","task_title":"设计确认方案","enabled":false,"approval_configurable":true,"duties":{}}]},{"stage_key":"RD13_validation_report","stage_name":"13 设计确认报告","enabled":true,"doc_tasks":[{"task_key":"rd_design_validation_report","task_title":"设计确认报告","enabled":false,"approval_configurable":true,"duties":{}}]}]},"activated_by":9,"activated_at":"2026-09-17T09:04:13.470161Z","created_by":9,"created_at":"2026-09-17T09:03:30.286085Z","updated_at":"2026-09-17T09:04:13.470161Z"}} diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/intake-doc-id.json b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/intake-doc-id.json new file mode 100644 index 00000000..e99837c4 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/intake-doc-id.json @@ -0,0 +1,3 @@ +{ + "doc_id": "doc_proj6424_intake" +} \ No newline at end of file diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/intake-final.md b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/intake-final.md new file mode 100644 index 00000000..b94bc9aa --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/intake-final.md @@ -0,0 +1,202 @@ +# 用户初始需求收集表 + +**项目**:rdev-s0-20260917-085054 +**阶段**:S0 设计输入摸底 +**撰写专员**:writer +**整合终审**:leader +**整理时间**:2026-09-17 + +--- + +## 结论 + +本次 S0 摸底阶段的输入材料极度稀缺。用户上传的 brief.md 仅含一句话:**"无创神经刺激器设计输入摸底。"**〔材料:brief.md〕 + +可锁定的事实基线如下:客户名称为**水木东方测试客户**,产品属于**二类有源医疗器械(神经刺激类)**,预期用途为**无创神经电刺激辅助改善目标症状**,目标注册市场为**中国 NMPA**。上述四项均来自 `project.md` 与 `blackboard.json` 的权威基线字段,并非从用户上传材料中抽取。〔来源:project.md / blackboard.json〕 + +**当前材料不足以支撑设计输入(DI)工作包启动。** 核心阻塞项包括:产品具体适应症/目标症状、技术参数、使用场景与使用者定位、临床评估路径,以及客户决策人信息。这些信息缺失将导致无法确定 NMPA 分类子路径、无法锁定适用标准、无法估算型检周期与注册成本。**下一步须通过商务渠道补齐上述信息,方可进入 DI 编写或型检规划阶段。**〔分析判断,无直接条文依据〕 + +--- + +## 产品与使用场景 + +### 结论句 + +**已知项**:产品为二类有源神经刺激器,属无创电刺激类,作用于神经系统。〔材料:brief.md、project.md〕 + +**未知项**:适应症(目标疾病/症状)、适用人群、使用环境(院内/家用)、操作流程、技术参数(刺激波形/频率/强度/通道数/供电方式)、禁忌症。 + +### 产品基本属性 + +| 维度 | 已知 | 待确认(G项对应) | +|---|---|---| +| 产品形态 | 二类有源医疗器械 | 具体形态(穿戴式/台式/手持式)**→ G02** | +| 管理类别 | 二类(已锁定) | 是否需做三类升级评审**→ G01** | +| 作用方式 | 无创神经电刺激 | 刺激部位、靶神经/靶区域**→ G01/G02** | +| 适应症 | 辅助改善"目标症状"(未定义) | 具体症状/疾病名称**→ G01(阻塞)** | +| 使用场景 | 未说明 | 医疗机构/家用**→ G03(阻塞)** | +| 使用者 | 未说明 | 专业人员/患者自用**→ G03(阻塞)** | +| 使用环境 | 未说明 | 医院/门诊/居家**→ G03** | +| 操作流程 | 未说明 | 每日频次/单次时长/疗程设计**→ G02** | + +### 解读 + +无创神经电刺激类设备在 NMPA 分类体系中常见于二类有源医疗器械,例如经皮电神经刺激仪(海关编码/注册分类对应 6826)、经颅电刺激仪、肌肉刺激仪等。但具体亚类须依据**作用靶点(外周神经/颅内神经/脊髓)和适应症**确认对应分类号。不同分类子路径对应不同的注册检验标准组合: + +- 若为**经颅刺激**(如经颅直流电刺激 tDCS、经颅电刺激 tES):须额外满足电磁兼容性(EMC)与电磁场安全要求,对应 GB 9706.1 系列中特定适用标准; +- 若为**外周神经刺激**(如周围神经电刺激仪):标准组合以通用电气安全(GB 9706.1)为主。 + +**本次无法判断具体分类路径与对应标准,取决于 G01(适应症)和 G02(技术参数)的补齐。**〔分析判断,无直接条文依据〕 + +### 对本项目的含义 + +在适应症和技术参数未知的前提下: +1. 无法为产品分配准确的 NMPA 注册分类子号; +2. 无法确定型检项目组合与试验周期; +3. 无法判断是否豁免临床试验或须提交临床评价资料; +4. 无法制定有针对性的竞品对标策略。 + +**结论:当前阶段不满足设计输入(DI)文件编写的前置条件,须优先完成信息补全。** + +--- + +## 客户诉求与约束 + +### 结论句 + +**客户诉求**:未知。现有材料仅表明"设计输入摸底"意图,未提供任何诉求细节、排期节点、预算范围或特殊约束。〔材料:brief.md〕 + +### 已知与待确认的诉求维度 + +| 维度 | 状态 | 说明 | +|---|---|---| +| 客户名称 | **已锁定** | 水木东方测试客户〔project.md / blackboard.json〕 | +| 时间要求 | **待确认**(G06) | 材料未提供任何时间节点或里程碑 | +| 预算范围 | **待确认**(G06) | 材料未提及 | +| 特殊监管约束 | **待确认**(G04) | 材料未说明是否已有临床数据、型检报告或同类注册历史 | +| 已有资料清单 | **待确认**(G08) | 材料未说明客户是否已持有检测报告、临床评估或设计文档 | +| 决策授权边界 | **待确认**(G05) | 材料未提及具体负责人或对接人 | + +### 解读 + +本次任务定性为 **S0 设计输入摸底**,符合从零启动新项目的特征。设计输入(Design Input)作为医疗器械质量管理体系(YY/T 0287 / ISO 13485)的核心输入文件,其启动条件要求至少具备:产品预期用途与适应症、基本技术性能要求、适用标准清单、使用场景与使用者定义。〔参考:YY/T 0287-2017 §5.3 设计开发输入〕 + +当前材料缺少以上全部要素,**若不补全即推进 DI,将导致文件无法通过设计评审(DCP),并在后续型检和注册阶段面临补充整改风险。** 用户偏好关注"关键研发排期、型检周期与备料冗余、法规标准合规与审评审批风险"(来源:user.md),但目前因基础参数缺失,上述任何一项均无法展开分析。**建议通过商务渠道一次性补全信息清单,避免反复拉锯。**〔分析判断,无直接条文依据〕 + +--- + +## 已有材料摘要 + +### brief.md + +| 项目 | 内容 | +|---|---| +| **文件路径** | `context/materials_text/brief.md` | +| **内容全文** | "无创神经刺激器设计输入摸底。" | +| **抽取事实** | 产品为无创神经刺激器;任务性质为设计输入摸底(S0 阶段) | +| **与本阶段结论的关系** | 仅定义了大类方向,无任何可支撑设计输入的参数 | +| **内部矛盾** | 无(材料过于简短,无内部矛盾可辨) | + +### _all.txt + +| 项目 | 内容 | +|---|---| +| **文件路径** | `context/materials_text/_all.txt` | +| **内容摘要** | 全文仅为 brief.md 的重复汇总,无额外材料 | +| **结论** | 本窗口无用户上传附件(如合同、规格书、会议纪要、检测报告、参考文献等) | + +**本阶段材料极度匮乏**,任何超出"无创神经刺激器"这一分类大方向的注册策略、技术选型或临床方案讨论,均属无材料支撑的分析,须待信息补全后重新评估。〔材料:brief.md〕 + +--- + +## 矛盾与疑点 + +本次输入材料不存在内部矛盾(因材料仅一句话)。与常规范例的偏离如下: + +| 项目 | 常规范例(S0 DI 启动包) | 本次实际 | 对本项目的影响 | +|---|---|---|---| +| 设计输入摸底 | 应含适应症、技术参数、预期性能、可用标准清单 | 仅一句话 | **阻塞**:无法开跑 DI | +| 二类有源器械 | 应有具体产品名称/型号、预期使用者、禁忌症 | 无 | **阻塞**:无法确定分类子路径 | +| NMPA 注册规划 | 应有目标注册证类型、时间线、型检安排 | 无 | **阻塞**:无法制定注册策略 | +| 用户决策链 | 应有项目负责人/对接人/决策授权人 | 无 | **阻塞**:无法确定信息补全渠道 | + +--- + +## 待确认清单 + +### 阻塞信息(无以下信息则无法开跑下一阶段) + +| # | 缺什么 | 为什么重要 | 优先级 | +|---|---|---|---| +| **G01** | **产品具体适应症/目标症状** | 决定 NMPA 分类子路径(不同适应症对应不同注册路径与标准组合),影响临床评价要求 | 最高 | +| **G02** | **技术参数**(刺激波形、频率范围、强度范围、通道数、供电方式、尺寸/重量、预期使用寿命) | 设计输入(DI)核心组成部分,也是型检报告的出具依据;技术参数缺失则 DI 文件无法通过评审 | 最高 | +| **G03** | **使用场景与使用者定位**(专业机构/家用;专业人员操作/患者自用) | 影响产品分类(是否涉及家用安全特殊要求)、适用标准(GB 9706.1 家用篇条款)、标签与说明书要求 | 高 | +| **G04** | **临床评估路径**(是否已有临床数据;是否具备豁免临床试验条件;临床评价资料是否已完成) | 直接影响注册周期与成本;若需补充临床试验,周期可能延长 12–36 个月 | 高 | +| **G05** | **客户决策人/对接人信息**(姓名、职务、联系方式、决策授权范围) | 须确认可向谁追问 G01–G04 及其他后续信息;无决策人则信息补全无渠道 | 高 | + +### 非阻塞信息(补充后可显著提升分析精度,不阻断 S0 框架搭建) + +| # | 缺什么 | 为什么重要 | 优先级 | +|---|---|---|---| +| **G06** | **预算范围与目标时间节点** | 影响注册路径选择(优先审批通道 vs. 常规通道);型检机构档期排期;临床试验方案规模 | 中 | +| **G07** | **竞争对手或同类已上市产品信息** | 参考设计输入对标;已有注册证信息可辅助判断分类路径与审评关注点 | 中 | +| **G08** | **已有检测报告或临床评估文档清单** | 判断是否可复用已有检测数据,减少重复检测费用与时间;若已有同类产品注册经历,可复用部分临床评价 | 中 | + +--- + +## 阻塞信息(字段快照) + +| 字段 | 值 | 来源 | +|---|---|---| +| 客户名称 | 水木东方测试客户 | project.md / blackboard.json | +| 产品类型/器械分类 | 二类有源医疗器械(神经刺激) | project.md / blackboard.json | +| 预期用途 | 无创神经电刺激辅助改善目标症状 | project.md / blackboard.json | +| 目标市场/注册区域 | 中国 NMPA | project.md / blackboard.json | + +--- + +## 非阻塞信息(字段快照) + +| 字段 | 值 | 状态 | +|---|---|---| +| 时间要求 | 未提供 | **待确认**(G06) | +| 预算范围 | 未提供 | **待确认**(G06) | +| 已有资料清单 | 未提供 | **待确认**(G08) | +| 特殊约束 | 未提供 | **待确认**(G04/G08) | +| 客户决策人/对接人 | 未提供 | **待确认**(G05) | + +--- + +## 本阶段材料快照 + +**原始材料**:brief.md(内容全文:`"无创神经刺激器设计输入摸底。"`) + +**前序组织产出**:01_organize/output.md(由 organizer 专员于 2026-09-17 整理,已归档至 `tasks/01_organize/output.md`) + +**本次撰写依据**:template.md(用户初始需求收集表模板)、blackboard.json(权威基线字段)、project.md(项目全局立项基线)、user.md(用户决策偏好与约束)、01_organize/output.md(前序事实整理报告) + +--- + +## 决策事项 + +**当前阶段无需拍板决策。** 本次交付为 S0 摸底阶段的文档基线终稿,旨在整理已知事实并显式化缺口,为后续商务信息补全提供结构化清单。 + +**下一步行动(面向工作流负责人)**: + +1. 通过商务渠道向水木东方测试客户获取 G01–G05(阻塞信息); +2. G06–G08(非阻塞信息)视项目推进节奏逐步补全; +3. 信息补全后,由技术专员依据更新后的事实基线,产出 DI 初稿或可行性评估报告。 + +--- + +## 自检清单(负责人终审执行) + +- [x] 模板每个章节均已写完,无残留括号提示 +- [x] 关键数字/路径/参数均已标注来源;无数字时标注"材料未提供"或"待确认" +- [x] 所有「待确认」项已在文末待确认清单中汇总(阻塞/非阻塞分开) +- [x] 无未标注的推测(分析判断类均标注"分析判断,无直接条文依据") +- [x] 专员已标注的出处均已保留 +- [x] 未从材料中抽取任何未提供的参数 +- [x] 正文各节均按四段式(结论句 → 列表/要点 → 解读 → 出处)展开 +- [x] 适用与不适用、机会与风险、已知与待确认均已显式覆盖 +- [x] 前序已批准文件(blackboard.json / project.md)与本阶段材料一致,无冲突 diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/intake-leader-AGENTS.md b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/intake-leader-AGENTS.md new file mode 100644 index 00000000..a06a8d22 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/intake-leader-AGENTS.md @@ -0,0 +1,61 @@ +## 角色 + +你是北京水木东方(医疗器械 CDMO)项目文档小队的商务对接负责人。你是用户与小队之间的唯一接口:专员向你汇报,只有你对用户说话、提交阶段文档。 + +你的价值不在于自己写长文,而在于把本阶段需求变成可验收的任务,审核专员产出,整合成一份可提交的 Markdown 终稿。结论短、论证完整:卡片可以短,阶段 Word 不能短。 + +## 汇报纪律 + +- 只有你可以把成果交给用户(通过系统落文档)。不要把未审核的专员原文直接当终稿。 +- 需要用户决策的事项一律上升,不要代用户拍板。 +- 专员产出不合格时退回说明差距;系统按剧本执行,你负责审核与整合。 + +## 本阶段你要做的 + +1. 用一句话回述本阶段交付物。 +2. 阅读快照、材料文本、前序文档和各专员 `output.md`。 +3. 按本阶段模板整合终稿,结论先行;与前序已批准文件保持一致。 +4. 缺信息标「待确认」,不要编造。 +5. 按 TASK.md 指定的交付文件落盘:终稿步写 `output.md`;若本步是「审核撰写计划」(review_plan),只写 `review_notes.md`,**禁止**把审核意见写入或覆盖 `output.md`。 +6. 专员已标注的出处必须保留;你整合时把能溯源的句子标上〔…〕,无依据的分析不要删,也不要补造引用。 + +## 汇报格式(终稿 output.md 开头;计划审核则写在 review_notes.md) + +**注意**:你整合生成的终稿文档结构必须严格遵循 `template.md` 的所有章节结构,不得自行替换为审阅报告结构!你的审阅和把关成果体现为:在保持 `template.md` 章节骨架(如 ## 结论、## 产品与使用场景、## 客户诉求与约束、## 已有材料摘要、## 待确认清单 等)的基础上,将专员的草稿进行逻辑润色、出处溯源和终审定稿输出。 + +**待确认清单**:在模板对应章节中集中列出文中所有「待确认」。 + + +## 写作质量 + +模板是章节骨架,不是篇幅上限。禁止把模板括号提示原样留下。卡片摘要可以短;阶段文档必须论证完整。结论短、论证完整。 + +### 详细 + +- 每一节至少包含:结论句 → 表格或列表(可用 Mermaid,图表要有标题) → 解读段落 → 支撑明细或出处。不要通篇只有列表。 +- 数字必须写清口径、假设、来源与日期。没有数字时写「未检索到公开信息」或「材料未提供」,并说明已尝试路径。 +- 表格禁止交空壳:至少填已知行;若确实无数据,用一行写明「为何为空」及待确认项。 +- 专员交给撰写岗的稿件要写完整论据,不要只交标题或提纲。 + +### 逻辑通顺 + +- 结论先行,后文不得与结论打架。写作过程中出现新事实,必须回写结论。 +- 章节按「事实 → 分析 → 对本项目的含义 → 建议或待拍板」推进。 +- 前序已批准文档与本阶段材料冲突时,两个都列出来并标记冲突,不默默取一边。 +- 选项对比用同一套维度(证据、周期、成本量级、风险、适用条件)。术语首次出现先定义。 +- 因果链写清:因 → 果 → 建议。不要跳跃到未交代的前提。 + +### 考虑全面 + +- 每份终稿显式覆盖:适用与不适用、机会与风险、优势与短板、已知与待确认、现在要用户做什么。没有决策则写「无需决策」。 +- 写推荐必须同时写否决或失效条件。 +- 能标出处的句子必须标〔…〕。无直接条文依据的分析保留,并标「(分析判断,无直接条文依据)」。 +- 会议纪要类短文档至少要有一个流程或责任矩阵。 + +### 自检(撰写岗与负责人必做) + +1. 模板中的每个章节是否都写完,没有残留括号提示。 +2. 关键数字、路径、参数前后是否一致,且可追溯。 +3. 文中所有「待确认」是否已在文末清单汇总。 +4. 是否有未标注的推测、疗效宣称或绝对化用语。 +5. 专员已标注的出处是否保留;无依据的分析是否被误删。 diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/main-instance-final.json b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/main-instance-final.json new file mode 100644 index 00000000..91f1b558 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/main-instance-final.json @@ -0,0 +1,175 @@ +{ + "instance": { + "id": 287, + "project_id": 6424, + "workflow_version_id": 93, + "instance_no": 1, + "status": "completed", + "config_revision": 4, + "plan_hash": "fa4721466a102c2cc4dc0d4a454e8ca684982571136b3f068d66fb428a417146", + "config_snapshot": { + "workflow_definition_key": "main", + "workflow_version": 2, + "workflow_version_id": 93, + "stages": [ + { + "stage_key": "V0.1_triage", + "stage_name": "V0.1 需求摸底", + "enabled": true, + "doc_tasks": [ + { + "task_key": "intake", + "task_title": "用户初始需求收集表", + "enabled": true, + "approval_configurable": true, + "duties": { + "author_user_id": 9, + "reviewer_user_id": 11, + "approver_user_id": 12 + } + } + ] + }, + { + "stage_key": "V0.5_feasibility", + "stage_name": "V0.5 方案与可行性", + "enabled": true, + "doc_tasks": [ + { + "task_key": "feasibility_dev", + "task_title": "设计开发可行性评估报告", + "enabled": false, + "approval_configurable": true, + "duties": {} + }, + { + "task_key": "feasibility_reg", + "task_title": "注册路径可行性评估报告", + "enabled": false, + "approval_configurable": true, + "duties": {} + }, + { + "task_key": "prelim_design", + "task_title": "系统初步设计方案", + "enabled": false, + "approval_configurable": true, + "duties": {} + }, + { + "task_key": "research", + "task_title": "调研报告", + "enabled": false, + "approval_configurable": true, + "duties": {} + }, + { + "task_key": "user_requirements", + "task_title": "用户需求表", + "enabled": false, + "approval_configurable": true, + "duties": {} + } + ] + }, + { + "stage_key": "V1.0_quoting", + "stage_name": "V1.0 商务报价", + "enabled": true, + "doc_tasks": [ + { + "task_key": "cdo_quote", + "task_title": "CDO 报价单", + "enabled": false, + "approval_configurable": true, + "duties": {} + } + ] + } + ] + }, + "activated_by": 9, + "activated_at": "2026-09-17T08:50:54.464545Z", + "created_by": 9, + "created_at": "2026-09-17T08:50:54.455933Z", + "updated_at": "2026-09-17T08:54:38.265556Z" + }, + "stages": [ + { + "id": 391, + "stage_key": "V0.1_triage", + "position": 10, + "enabled": true, + "status": "completed", + "doc_tasks": [ + { + "id": 323, + "task_key": "intake", + "enabled": true, + "status": "pending", + "approved": false + } + ] + }, + { + "id": 392, + "stage_key": "V0.5_feasibility", + "position": 20, + "enabled": true, + "status": "completed", + "doc_tasks": [ + { + "id": 324, + "task_key": "feasibility_dev", + "enabled": false, + "status": "skipped_disabled", + "approved": false + }, + { + "id": 325, + "task_key": "feasibility_reg", + "enabled": false, + "status": "skipped_disabled", + "approved": false + }, + { + "id": 326, + "task_key": "prelim_design", + "enabled": false, + "status": "skipped_disabled", + "approved": false + }, + { + "id": 327, + "task_key": "research", + "enabled": false, + "status": "skipped_disabled", + "approved": false + }, + { + "id": 328, + "task_key": "user_requirements", + "enabled": false, + "status": "skipped_disabled", + "approved": false + } + ] + }, + { + "id": 393, + "stage_key": "V1.0_quoting", + "position": 30, + "enabled": true, + "status": "completed", + "doc_tasks": [ + { + "id": 329, + "task_key": "cdo_quote", + "enabled": false, + "status": "skipped_disabled", + "approved": false + } + ] + } + ] +} \ No newline at end of file diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/pi-intake-meta.json b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/pi-intake-meta.json new file mode 100644 index 00000000..dd2d81f2 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/pi-intake-meta.json @@ -0,0 +1,28 @@ +{ + "create_http": 202, + "run_id": "run_1789635054471569201", + "final": { + "RunID": "run_1789635054471569201", + "SessionID": "sess-rdev-s0-p6424-intake", + "ProjectID": 6424, + "UserID": 9, + "ClientTurnID": "rdev-s0-intake-1789635054", + "IdempotencyKey": "turn:sess-rdev-s0-p6424-intake:rdev-s0-intake-1789635054", + "TaskKey": "intake", + "Stage": "", + "WorkflowInstanceID": 287, + "StageInstanceID": 391, + "WorkflowStageKey": "V0.1_triage", + "Status": "completed", + "WorkspaceID": "/app/data/workspaces/bizdev/intake_1789635054485631143", + "AssistantMsgID": 3329, + "WorkerID": "", + "LeaseExpiresAt": null, + "CreatedAt": "2026-09-17T08:50:54.471673298Z", + "UpdatedAt": "2026-09-17T08:54:25.885010407Z", + "ErrorMessage": "", + "Attempt": 1, + "resumable": false + }, + "duration_ms": 220109 +} \ No newline at end of file diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/pi-rd_design_input_spec-meta.json b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/pi-rd_design_input_spec-meta.json new file mode 100644 index 00000000..998412d0 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/pi-rd_design_input_spec-meta.json @@ -0,0 +1,23 @@ +{ + "RunID": "run_1789635960880707641", + "SessionID": "sess-rdev-s0-p6425-di3", + "ProjectID": 6425, + "UserID": 9, + "ClientTurnID": "rdev-di3-1789635960", + "IdempotencyKey": "turn:sess-rdev-s0-p6425-di3:rdev-di3-1789635960", + "TaskKey": "rd_design_input_spec", + "Stage": "", + "WorkflowInstanceID": 291, + "StageInstanceID": 396, + "WorkflowStageKey": "RD03_design_input", + "Status": "completed", + "WorkspaceID": "/app/data/workspaces/bizdev/rd_design_input_spec_1789635960900711737", + "AssistantMsgID": 3359, + "WorkerID": "", + "LeaseExpiresAt": null, + "CreatedAt": "2026-09-17T09:06:00.880788098Z", + "UpdatedAt": "2026-09-17T09:13:28.353775223Z", + "ErrorMessage": "", + "Attempt": 1, + "resumable": false +} \ No newline at end of file diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/project.json b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/project.json new file mode 100644 index 00000000..5e586eb9 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/project.json @@ -0,0 +1,20 @@ +{ + "id": 6424, + "code": "rdev-s0-2026-76bc6575", + "name": "rdev-s0-20260917-085054", + "customer_name": "水木东方测试客户", + "device_type": "二类有源医疗器械(神经刺激)", + "intended_use": "无创神经电刺激辅助改善目标症状", + "target_market": "中国 NMPA", + "product_domain": "medical_device", + "current_stage": "V0.1_triage", + "environment": "dev", + "status": "active", + "creator_user_id": 9, + "lifecycle_status": "planning", + "active_workflow_key": "", + "workflow_selection_version": 1, + "workflow_plan_revision": 0, + "created_at": "2026-09-17T08:50:54.444179634Z", + "updated_at": "2026-09-17T08:50:54.444179634Z" +} \ No newline at end of file diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/rd_design_input_spec-docgov.json b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/rd_design_input_spec-docgov.json new file mode 100644 index 00000000..3e533c00 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/rd_design_input_spec-docgov.json @@ -0,0 +1,40 @@ +{ + "id": 293, + "doc_id": "doc_proj6425_rd_design_input_spec", + "project_id": 6425, + "task_key": "rd_design_input_spec", + "title": "设计输入规格书", + "stage": "RD03_design_input", + "version": 1, + "current_state": "drafting", + "is_locked": false, + "is_template_only": false, + "content_sha256": "3b763a3488dbd4fab8d7793f90b46f3373457f3745f3906b3c33e2bd39af39dc", + "work_dir": "/app/data/workspaces/bizdev/rd_design_input_spec_1789635960900711737", + "author_id": 9, + "author_name": "系统管理员", + "reviewer_id": 11, + "reviewer_name": "李主管", + "approver_id": 12, + "approver_name": "王总监", + "author_claimed": false, + "author_claimed_at": null, + "author_last_viewed_at": null, + "author_last_edited_at": null, + "reviewer_claimed": false, + "reviewer_claimed_at": null, + "approver_claimed": false, + "approver_claimed_at": null, + "last_rejected_reason": "", + "last_rejected_by_role": "", + "last_rejected_by_name": "", + "last_rejected_at": null, + "approved_at": null, + "config": { + "reject_rollback_to": "drafting", + "allow_approver_to_reviewer": true, + "require_author_confirm_on_reject": true + }, + "created_at": "2026-09-17T09:06:00.895726405Z", + "updated_at": "2026-09-17T09:13:28.349118981Z" +} \ No newline at end of file diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/rd_design_input_spec-final.md b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/rd_design_input_spec-final.md new file mode 100644 index 00000000..0db7fc11 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/rd_design_input_spec-final.md @@ -0,0 +1,391 @@ +# 设计输入规格书 + +| 字段 | 值 | +|---|---| +| 项目 | rdev-s0-6425 | +| 文件编号 | RD-DI-SPEC | +| 记录归属 | DHF(设计历史文件) | +| 版本 | A | +| 阶段 | 03 设计输入 | +| 编制依据快照 | ws_rd_design_input_spec_1789635960900794034 | +| 编制日期 | 2026-09-17 | + +--- + +## 结论 + +**本规格书适用性:条件成立,存在高优先级缺口待确认。** + +依据现有用户材料(design_input_brief.md + upload_material_design_inputrief.md.md,内容完全一致)已可建立设计输入规格书的四个核心章节骨架。然而,五项高优先级缺口(S-01~S-05)尚未闭环,直接影响功能边界确定、安全参数设计、型检送检方案与临床评价范围界定。**在以下缺口获得用户正式确认前,不得进入详细设计阶段。** + +关键风险锚点: +- 刺激强度上限未定义,将导致过流保护整定值(DI-S-001)无法参数化,型检送检受阻; +- 预期用途未由用户在材料中正式签署确认,存在设计开发范围蔓延风险; +- YY 9706.210 专用安全标准适用性未确认,输出限制设计存在合规隐患。 + +--- + +## 适用性 + +| 项目 | 结论 | 理由 | +|---|---|---| +| 本文件适用性 | **适用** | 项目已锁定为「二类有源医疗器械(神经刺激)」,目标市场为 NMPA;用户材料提供了功能/性能/安全/法规四个维度的摸底陈述,满足设计输入编制的起点条件 | +| DHF 适用性 | **适用** | 依据 ISO 13485 第 7.1 条及 GB 9706.1-2022 第 4 条,设计开发阶段须建立并保持设计历史文件(DHF),本文件为其组成部分 | +| ISO 14971 风险管理要求 | **适用** | 材料明确要求「ISO 14971」风险管理框架,本文件须纳入风险管理文档追溯链 | +| 是否因缺项声明不适用 | **否** | 虽存在大量「待确认」项,但用户材料已提供部分功能/性能/法规事实基底,可编制骨架;缺口不影响本阶段文档本身的必要性 | + +--- + +## 一、功能要求 + +### 结论 + +用户材料已明确四项核心功能(脉冲刺激、强度可调、会话计时、紧急停止)〔材料:design_input_brief.md〕,构成功能基线。**强度上限、输出波形(单相/双相、恒流/恒压)、通道数为高优先级缺口,须确认为 DI-F-002/003/004 后方可冻结功能规格。** + +### 事实表 + +| ID | 功能陈述 | 优先级 | 来源 | 验证方式 | +|---|---|---|---|---| +| DI-F-001 | **脉冲刺激输出**:通过皮肤表面电极施加电脉冲,触发目标神经/肌肉兴奋 | 🔴 高 | 材料原文〔材料:design_input_brief.md 功能章〕 | 型检(输出波形、频率、脉宽);临床性能测试 | +| DI-F-002 | **强度可调**:输出幅度(电流或电压)在用户指定范围内连续可调 | 🔴 高 | 材料原文〔材料:design_input_brief.md 功能章〕 | 型检(量程、精度);可用性测试(操作验证) | +| DI-F-003 | **会话计时**:记录并显示单次治疗时长 | 🟡 中 | 材料原文〔材料:design_input_brief.md 功能章〕 | 功能测试 | +| DI-F-004 | **紧急停止**:用户可一键切断所有输出,停止刺激 | 🔴 高 | 材料原文〔材料:design_input_brief.md 功能章〕 | 型检(安全功能测试);可用性测试 | +| DI-F-005 | **刺激频率可调**:范围 1–100 Hz | 🟡 中 | 材料原文〔材料:design_input_brief.md 性能章〕 | 型检 | +| DI-F-006 | **脉宽可调**:范围 50–500 µs | 🟡 中 | 材料原文〔材料:design_input_brief.md 性能章〕 | 型检 | +| DI-F-007 | **过流保护**:输出电流超过预设阈值时自动关断 | 🔴 高 | 材料原文〔材料:design_input_brief.md 安全章〕 | 型检(GB 9706.1-2022 §8.7);过流保护功能测试 | +| DI-F-008 | **电极脱落检测**:检测到电极与皮肤接触不良时告警或自动切断 | 🔴 高 | 材料原文〔材料:design_input_brief.md 安全章〕 | 型检;危害分析验证 | +| DI-F-009 | **输出波形类型**(单相/双相、恒流/恒压) | **待确认** | 上游缺口 S-02 | — | +| DI-F-010 | **独立刺激通道数**(单通道/双通道) | **待确认** | 上游缺口 | — | +| DI-F-011 | **用户界面类型**(物理按键/触摸屏/APP) | **待确认** | 上游缺口 | — | + +### 解读 + +**功能覆盖分析**:材料所述功能覆盖了经皮神经电刺激(TENS)类设备的基本操作流程。用户(操作者)角色在材料中未定义,推定以非专业医护人员(或在受控环境/家用场景使用)为假设。 + +**操作流程推断**:基于四项核心功能,操作流程至少包含:开机 → 参数设置(频率/脉宽/强度)→ 开始治疗 → 计时运行 → 紧急停止 → 结束复位。该流程须在可用性工程文档中细化。 + +**缺口传递**:DI-F-002 的「强度范围」是安全上限的核心锚点——若 100 Hz 与 500 µs 上限为设备物理边界而非临床安全边界,则强度上限须另行确定,并与过流保护整定值联动设计。DI-F-009(输出波形类型)影响电极设计、EMC 测试布置与危害分析,须在详细设计前确认。 + +**已知缺口**: + +| 缺口 ID | 缺口描述 | 影响 | +|---|---|---| +| S-02 | 刺激强度上限未定义 | 与 DI-F-002 联动,无法完成强度量程设计 | +| S-04 | 目标人群与禁忌症未定义 | 影响功能适用范围声明 | + +--- + +## 二、性能要求 + +### 结论 + +用户材料已给出频率与脉宽的数值范围〔材料:design_input_brief.md〕,可填入 DI-P-001/002。**刺激强度上限(电流峰值或电压峰值)完全缺失,属最高优先级缺口;精度指标、量程边界、测量条件均未定义,须在 DI-P-003/004 中补充。** + +### 事实表 + +| ID | 性能指标 | 目标值/范围 | 测量条件 | 来源 | +|---|---|---|---|---| +| DI-P-001 | 刺激频率 | 1–100 Hz | 额定负载、室温 23°C ±2°C(推定) | 材料原文〔材料:design_input_brief.md 性能章〕 | +| DI-P-002 | 刺激脉宽 | 50–500 µs | 额定负载、室温(推定) | 材料原文〔材料:design_input_brief.md 性能章〕 | +| DI-P-003 | **输出强度上限**(电流峰值 mA 或电压峰值 V) | **待确认** | — | 上游缺口 S-02 | +| DI-P-004 | **输出波形**(单相/双相、恒流/恒压) | **待确认** | — | 上游缺口 S-02 | +| DI-P-005 | **通道数**(独立刺激通道数量) | **待确认** | — | 上游缺口 | +| DI-P-006 | **频率设置精度** | **待确认** | — | — | +| DI-P-007 | **脉宽设置精度** | **待确认** | — | — | +| DI-P-008 | **强度设置精度** | **待确认** | — | — | +| DI-P-009 | **输出启动上升时间** | **待确认** | — | — | +| DI-P-010 | **预热时间/启动稳定时间** | **待确认** | — | — | +| DI-P-011 | **输出噪声/纹波** | **待确认** | — | — | +| DI-P-012 | **预期使用寿命** | **待确认** | — | 上游缺口 S-10 | + +### 解读 + +**参数范围分析**:频率 1–100 Hz、脉宽 50–500 µs 的范围与主流经皮神经电刺激(TENS)设备文献一致(分析判断,无直接条文依据),但材料未提供该上限的来源说明。 + +**上限性质判定**:100 Hz 与 500 µs 可能代表: +1. 临床有效剂量上限(安全约束); +2. 设备硬件输出能力上限(工程约束); +3. 两者兼有。 + +若为硬件能力边界,则强度上限须另行确定,不受频率/脉宽上限约束;若为临床安全边界,则强度上限须与该边界联动确定。需在 S-02/S-03 中澄清。 + +**与标准的潜在约束关系**:依据工程师阶段分析,YY 9706.210-2021(对应 IEC 60601-2-10:2016)第 6.8 条对神经刺激器输出有限制要求。材料所述 1–100 Hz、50–500 µs 与该标准限制范围大致吻合,但需待 YY 9706.210 适用性确认后(DI-R-004)进行正式比对。 + +**已知缺口**: + +| 缺口 ID | 缺口描述 | 影响 | +|---|---|---| +| S-02 | 刺激强度上限未定义 | 阻断 DI-P-003 参数化,无法确定过流保护阈值 | +| S-03 | 频率/脉宽上限来源未确认 | 影响是否与 YY 9706.210 §6.8 比对 | +| S-10 | 预期使用寿命未定义 | 影响 DI-P-012 可靠性指标 | + +--- + +## 三、接口与环境要求 + +### 结论 + +用户材料仅提供 USB 充电与工作温度 5–40°C 两项,存在大量缺项。**使用环境(医疗机构/家用)、IP 防护等级、湿度范围、EMC 版次、供电电压范围均未定义,其中 YY 9706.102 版次(第 3 版 vs 第 4 版)对 EMC 测试方案有显著影响,须优先确认(S-06)。** + +### 事实表 + +| ID | 接口/环境项 | 要求陈述 | 适用边界 | 来源 | +|---|---|---|---|---| +| **电气接口** ||||| +| DI-I-001 | 充电接口 | USB 充电 | — | 材料原文〔材料:design_input_brief.md 接口章〕 | +| DI-I-002 | 供电方式 | 锂电池供电(推定,需确认) | — | 工程推断,无直接材料依据 | +| DI-I-003 | 额定输入电压范围 | **待确认** | — | — | +| DI-I-004 | 电极连接器规格 | **待确认** | — | — | +| **用户界面** ||||| +| DI-I-005 | 用户界面类型 | **待确认** | — | 上游缺口 | +| DI-I-006 | 显示屏规格 | **待确认** | — | — | +| **机械接口** ||||| +| DI-I-007 | 设备尺寸约束 | **待确认** | — | — | +| DI-I-008 | 设备重量约束 | **待确认** | — | — | +| **使用环境** ||||| +| DI-I-009 | 工作温度 | 5–40°C | 室内常规环境 | 材料原文〔材料:design_input_brief.md 接口章〕 | +| DI-I-010 | 相对湿度 | **待确认** | — | 上游缺口 G-05 | +| DI-I-011 | 大气压力(海拔) | **待确认** | — | 上游缺口 G-05 | +| DI-I-012 | 防护等级(IP 等级) | **待确认** | — | 上游缺口 G-05 | +| DI-I-013 | 使用环境(医疗机构/家用/公共场所) | **待确认** | — | 上游缺口 S-05 | + +### 解读 + +**使用环境判定的影响**:若设备预期用于家用,则须额外满足 GB 9706.1-2022 第 16 条(家用医用电气设备补充要求)及 YY 9706.111-2021(如适用);若预期用于医疗机构,则须满足 GB 9706.1-2022 第 16 条(医用电气设备通用要求)基本安全要求。两种场景对 IP 防护等级要求与 EMC 测试组别要求不同。 + +**USB 充电的隐含要求**:USB 充电接口须满足 GB 4943.1(信息技术设备安全)或 YY 9706.1-2022 第 16 条对电源适配器的相关要求,且须考虑充电接口的电气安全设计(漏电流、绝缘)。 + +**已知缺口**: + +| 缺口 ID | 缺口描述 | 影响 | +|---|---|---| +| S-05 | 使用环境(家用/医疗)未确认 | 影响 YY 9706.111 适用性、EMC 测试组别 | +| S-06 | YY 9706.102 版次未确认 | 影响 EMC 测试方案,返工风险 | +| G-05 | 环境参数(湿度/海拔/IP等级)未细化 | 影响型检环境测试项目 | + +--- + +## 四、安全与风险输入 + +### 结论 + +用户材料明确要求过流保护与电极脱落检测,并指定 ISO 14971 风险管理框架〔材料:design_input_brief.md 安全章〕,构成 DI-S-001/002/003 的基础。但危害分析尚未开展,剩余风险接受准则、危害情境清单、已知禁忌均未提供。**在危害分析完成前,安全与风险输入章节不得关闭。** + +### 事实表 + +| ID | 安全/风险输入 | 关联危害/控制措施 | 验证/确认线索 | 来源 | +|---|---|---|---|---| +| DI-S-001 | **过流保护**:输出电流超过预设阈值时自动关断 | 过高电流导致组织热损伤/神经损伤 | 型检 GB 9706.1-2022 §8.7;过流保护功能测试;阈值整定值验证 | 材料原文〔材料:design_input_brief.md 安全章〕 | +| DI-S-002 | **电极脱落检测**:电极接触中断时告警或自动关断 | 电极脱落导致开路高电压/皮肤刺痛 | 型检;危害分析验证 | 材料原文〔材料:design_input_brief.md 安全章〕 | +| DI-S-003 | **紧急停止功能**:用户可一键切断所有输出 | 操作失误时快速终止刺激 | 型检安全功能测试;可用性测试 | 材料原文〔材料:design_input_brief.md 安全章〕 | +| DI-S-004 | **风险管理框架**:满足 ISO 14971:2019 | 须建立风险管理文档,纳入 DHF | 风险管理文档 | 材料原文〔材料:design_input_brief.md 安全章〕 | +| DI-S-005 | **刺激强度上限**(关联 DI-P-003) | 最高优先级:与过流保护整定值直接联动;未定义则过流保护阈值无法确定 | S-02 待确认 | 上游缺口 S-02 | +| DI-S-006 | **禁忌症清单** | 心脏起搏器植入者、癫痫患者等高风险人群——材料未提供 | 临床评价/文献调研 | 上游缺口 S-04 | +| DI-S-007 | **剩余风险接受准则** | ISO 14971:2019 §5.4 要求明确;材料未提供 | 风险管理计划 | 上游缺口 G-03 | +| DI-S-008 | **生物相容性要求**(BGP 电极与皮肤接触) | 与人体接触部件须进行生物相容性评价 | S-08 待确认 | 上游缺口 S-08 | +| DI-S-009 | **输出电压上限**(恒压模式适用) | 开路条件下电压不得超过安全限值 | 与电极脱落检测联动设计 | 上游缺口 S-02 | + +### 解读 + +**过流保护与强度上限的耦合关系**:过流保护(DI-S-001)的有效性与刺激强度上限(DI-P-003)强耦合。若设备标称最大输出强度为 I_max,则过流保护阈值须设定在 I_max 附近且留有适当余量。用户材料未给出强度上限,导致 DI-S-001 无法完成参数化设计。 + +**电极脱落检测的电压安全**:在恒压输出模式下,若电极脱落,负载突然增大可能导致电压骤升,危及患者。须在危害分析中明确控制策略(电压钳位、限流、告警等),并在 DI-S-009 中记录电压上限要求。 + +**YY 9706.210 的叠加约束**:若 DI-R-004(YY 9706.210)适用性确认,则第 6.8 条「输出限制」将对输出参数形成额外约束。须在危害分析中比对标准条款与用户材料参数的差异。 + +**已知缺口**: + +| 缺口 ID | 缺口描述 | 影响 | +|---|---|---| +| S-02 | 刺激强度上限未定义 | 阻断 DI-S-001 参数化 | +| S-04 | 禁忌症未定义 | 影响标签/说明书,审评发补风险 | +| S-08 | 生物相容性要求未定义 | 影响与人体接触部件评价 | +| G-03 | 剩余风险接受准则未定义 | ISO 14971 符合性缺失 | + +--- + +## 五、法规与标准符合性 + +### 结论 + +用户材料列举了 GB 9706.1、YY 9706.102 与 ISO 14971 三项标准依据〔材料:design_input_brief.md 法规章〕,可建立初步符合性框架。但存在两项关键缺项:**YY 9706.210(神经刺激专用安全标准)适用性未确认;YY 9706.102 的版次(2021 版对应第 3 版;新版第 4 版征求意见中)未确认,直接影响 EMC 检测方案。** + +### 法规/标准符合性表 + +| ID | 法规/标准 | 适用条款/要点 | 对本设计输入的含义 | 符合性证据计划 | +|---|---|---|---|---| +| DI-R-001 | **GB 9706.1-2022**(医用电气设备 通用安全要求,等同采用 IEC 60601-1:2005+AMD1:2012+AMD2:2020) | 通用安全要求;第 8.7 条(保护导体/过流保护);第 16 条(医用电气设备补充要求) | 所有安全设计须满足;过流保护属于第 8.7 条强制要求 | 型检报告;设计验证报告 | +| DI-R-002 | **YY 9706.102-2021**(医用电气设备 第 1-2 部分:通用安全要求 并列标准 电磁兼容 要求及试验,对应 IEC 60601-1-2:2014 第 3 版) | 全项目 EMC 测试;发射、抗扰度 | 须完成注册检测;**版次(S-06)待确认**:若新版 YY 9706.102(对应 IEC 60601-1-2:2018 第 4 版)生效,测试项目有调整 | 型检报告 | +| DI-R-003 | **ISO 14971:2019**(医用器件风险管理应用) | 风险管理全过程要求;第 5 章危害识别、第 6 章风险估计、第 7 章风险控制 | 须建立风险管理文档(DHF 组成文件);所有设计输入须有风险考量 | 风险管理文档(RM-DOC) | +| DI-R-004 | **YY 9706.210-2021**(医用电气设备 第 2-10 部分:神经和肌肉刺激器的基本性能与基本安全要求,对应 IEC 60601-2-10:2016) | 神经刺激器专用安全与性能要求;第 6.8 条输出限制、说明书要求 | **须确认本产品是否适用**(若预期用途为神经刺激,大概率适用);若适用则额外增加约束 | 型检报告;适用性分析报告 | +| DI-R-005 | **GB/T 25000.51-2016**(系统与软件工程 系统与软件质量要求与评价(SQuaRE) 第 51 部分) | 软件质量要求;就绪可用产品 | 若含嵌入式软件,须满足此标准 | 软件测试报告 | +| DI-R-006 | **YY 9706.111-2021**(医用电气设备 第 1-11 部分:通用安全和基本性能通用要求 并列标准:家庭护理环境使用的医用电气设备的要求) | 家用环境补充安全要求 | **若设备预期用于家用(S-05),须满足**;会影响 EMC 测试组别与温湿度测试条件 | 型检报告 | +| DI-R-007 | **医疗器械网络安全注册技术审查指导原则(2022年版)** | 网络安全基本要求、数据接口安全 | 若含网络/蓝牙/Wi-Fi 功能(S-07),须满足 | 网络安全评价报告(如适用) | + +### 解读 + +**YY 9706.210 的核心地位**:DI-R-004(YY 9706.210)对神经刺激设备是核心标准,与通用安全标准形成叠加约束。例如,YY 9706.210 第 6.8 条对输出能量有明确限制,若本产品频率上限 100 Hz、脉宽上限 500 µs 与 YY 9706.210 的限制不一致,则须在设计中遵守更严格的标准。若 DI-R-004 确认适用,则 DI-P-001/002 的上限值可能受到该标准的约束(而非仅由材料给出),需在 S-03 中重新对齐。 + +**EMC 版次的窗口期风险**:GB 9706.1-2022 已发布实施,IEC 60601-1-2:2018(第 4 版)对应的 YY 9706.102 修订版可能在近期生效。若 NMPA 在型检时已要求新版,则测试项目将有调整(新增无线共存测试等)。S-06 须在型检送检前确认。 + +**已知缺口**: + +| 缺口 ID | 缺口描述 | 影响 | +|---|---|---| +| S-03 | YY 9706.210 适用性未确认 | 专用安全要求可能遗漏 | +| S-05 | 使用环境未确认 | YY 9706.111 适用性不明 | +| S-06 | YY 9706.102 版次未确认 | EMC 测试方案存在返工风险 | +| S-07 | 软件需求未确认 | GB/T 25000.51 符合性无法保证 | + +--- + +## 六、追溯矩阵 + +| 本文件 ID | 上游(输入/需求来源) | 下游(输出/验证/确认) | +|---|---|---| +| **RD-DI-SPEC**(本文件) | 01_organize/output.md(事实清单);用户材料(design_input_brief.md) | 设计开发计划(DD-DP);危害分析报告(RM-HAZ);设计验证报告(DD-VR);型检送检清单;风险管理文档(RM-DOC) | +| DI-F-001(脉冲刺激输出) | 材料:design_input_brief.md 功能章 | DD-VR 功能测试;型检功能测试 | +| DI-F-002(强度可调) | 材料:design_input_brief.md 功能章 | DD-VR 强度量程测试;型检 | +| DI-F-003(会话计时) | 材料:design_input_brief.md 功能章 | DD-VR 功能测试 | +| DI-F-004(紧急停止) | 材料:design_input_brief.md 功能章 | DD-VR 安全功能测试;型检;可用性测试 | +| DI-F-005/006(频率/脉宽可调) | 材料:design_input_brief.md 性能章 | 型检性能测试 | +| DI-F-007(过流保护) | 材料:design_input_brief.md 安全章 | 型检 GB 9706.1-2022 §8.7 | +| DI-F-008(电极脱落检测) | 材料:design_input_brief.md 安全章 | 型检;危害分析验证 | +| DI-P-001/002(频率/脉宽范围) | 材料:design_input_brief.md 性能章 | 型检性能测试 | +| DI-P-003/004(强度/波形) | **待确认 S-02** | — | +| DI-I-001(USB充电) | 材料:design_input_brief.md 接口章 | 型检安全测试 | +| DI-I-009(工作温度) | 材料:design_input_brief.md 接口章 | 型检环境测试 | +| DI-S-001/002/003(安全功能) | 材料:design_input_brief.md 安全章 + ISO 14971 | RM-HAZ;型检安全测试 | +| DI-R-001(GB 9706.1-2022) | 材料:design_input_brief.md 法规章 | 型检报告 | +| DI-R-002(YY 9706.102) | 材料:design_input_brief.md 法规章 | 型检报告 | +| DI-R-003(ISO 14971) | 材料:design_input_brief.md 法规章 | RM-DOC | +| DI-R-004(YY 9706.210) | 工程推断(无直接材料依据) | 型检报告;适用性分析报告 | + +--- + +## 七、已有材料摘要 + +### 7.1 核心原始材料 + +| 来源 | 可用内容 | 局限性 | +|---|---|---| +| design_input_brief.md(主材料) | 功能4项、性能2项、接口2项、安全3项、法规3项 | 无预期用途正式陈述、无强度上限、无可靠性指标、无用户/环境详细描述 | +| upload_material_design_input_brief.md.md | 内容与主材料完全相同 | 同上 | +| 02_engineer/output.md | 已提取事实清单、11项缺口、5项矛盾、技术路线分析 | 缺口均为「待确认」,未获用户正式确认 | + +### 7.2 项目级基线 + +| 来源 | 锁定内容 | +|---|---| +| project.md | 产品类型(二类有源神经刺激)、预期用途立项定义「无创神经电刺激辅助改善目标症状」、目标市场(NMPA) | +| blackboard.json | 客户名称(水木东方测试客户)、设备类型、目标市场 | + +### 7.3 矛盾与冲突记录 + +| 编号 | 矛盾描述 | 材料A | 材料B/对照 | 处理方式 | +|---|---|---|---|---| +| C-01 | 预期用途来源 | 材料本身无 intended_use 陈述 | project.md 定义为「无创神经电刺激辅助改善目标症状」 | **标记为 S-01,用户确认前不得作为正式设计输入** | +| C-02 | 频率上限来源不清 | 材料写 1–100 Hz | 立项定义为二类有源神经刺激,临床常用频率可达 200 Hz | **标记为 S-03,确认为临床安全上限还是硬件能力上限** | +| C-03 | 脉宽上限来源不清 | 材料写 50–500 µs | 神经刺激文献常用上限可达 1000 µs | **标记为 S-03,同上** | +| C-04 | EMC 标准版次未确认 | 材料写 YY 9706.102 | GB 9706.1-2022 已发布,YY 9706.102 对应 IEC 60601-1-2:2014 第 3 版;**第 4 版** IEC 60601-1-2:2018 已发布(YY 9706.102 修订中) | **标记为 S-06,确认适用版次** | +| C-05 | YY 9706.210 适用性未确认 | 材料未提及此标准 | 神经刺激设备大概率适用 YY 9706.210-2021 | **标记为待确认,DI-R-004 中记录** | + +--- + +## 八、风险清单 + +| 风险 ID | 风险描述 | 影响 | 概率 | 优先级 | 缓控措施 | +|---|---|---|---|---|---| +| R-01 | **刺激强度上限未定义 → 过流保护整定值无法确定 → 型检无法完成送检** | 设计阶段冻结受阻 | 高 | 🔴 极高 | 优先安排 S-02 确认 | +| R-02 | **预期用途未由用户正式确认 → 临床评价范围无法确定 → 注册发补风险** | 注册路径受阻 | 高 | 🔴 极高 | 安排 S-01 确认,并在设计历史记录中注明来源 | +| R-03 | **YY 9706.210 适用性未确认 → 专用安全要求遗漏 → 型检报告缺陷** | 型检不通过 | 中 | 🔴 高 | 安排 S-03/S-06 同步确认 | +| R-04 | **使用环境(家用/医疗)未确认 → YY 9706.111 适用性不明 → EMC 测试组别错误 → 型检返工** | 型检周期延长 3–6 个月 | 中 | 🟡 中 | 安排 S-05 确认 | +| R-05 | **禁忌症未定义 → 标签/说明书缺失 → 审评发补** | 注册发补 | 中 | 🟡 中 | 安排 S-04 确认 | +| R-06 | **嵌入式软件无需求 → GB/T 25000.51 符合性缺失 → 审评发补** | 注册发补 | 中 | 🟡 中 | 安排 S-07 确认 | +| R-07 | **无可靠性指标 → 使用寿命声明无依据 → 审评要求补充** | 注册发补/设计返工 | 低 | 🟡 中 | 安排 S-10 确认 | +| R-08 | **生物相容性要求缺失 → 与人体接触部件评价无法闭环** | 生物相容性测试缺失 | 低 | 🟡 中 | 安排 S-08 确认 | + +--- + +## 九、待确认清单 + +> 以下事项须由用户在进入详细设计前正式确认。按优先级排序,建议优先处理高优先级项。 + +| 序号 | 确认项 | 优先级 | 关联章节 | 不确认的后果 | +|---|---|---|---|---| +| **S-01** | **预期用途(Intended Use)是否以「无创神经电刺激辅助改善目标症状」为准?** 须用户正式签署确认。 | 🔴 高 | 功能要求;法规与标准 | 临床评价范围无法确定,注册路径存在不确定性 | +| **S-02** | **刺激强度上限(电流峰值 mA 或电压峰值 V)是多少?** 与过流保护整定值(DI-S-001)直接联动,须同步确定。 | 🔴 高 | 性能要求;安全与风险 | 过流保护参数无法确定,型检无法完成 | +| **S-03** | **频率上限 100 Hz、脉宽上限 500 µs 的来源:** 为临床有效剂量上限(安全约束)还是设备硬件能力边界(工程约束)?若为安全约束,则须与 YY 9706.210-2021 §6.8 比对确认。 | 🔴 高 | 性能要求;法规与标准 | YY 9706.210 适用性无法判断,输出限制设计存在风险 | +| **S-04** | **目标人群(年龄、疾病状态)与禁忌症清单是什么?** 影响临床评价、标签与说明书。 | 🔴 高 | 安全与风险;功能要求 | 禁忌症未定义,审评发补风险 | +| **S-05** | **使用环境是否为家用环境(家庭护理环境)?** 若是,须满足 YY 9706.111-2021;EMC 测试组别亦受影响。 | 🟡 中 | 接口与环境;法规与标准 | YY 9706.111 适用性不明,型检方案存在返工风险 | +| **S-06** | **YY 9706.102(EMC)采用 2021 版(第 3 版,对应 IEC 60601-1-2:2014)还是最新版(第 4 版,IEC 60601-1-2:2018)?** 须确认 NMPA 当前接受的版本。 | 🟡 中 | 接口与环境;法规与标准 | EMC 测试方案无法确定 | +| **S-07** | **是否含嵌入式软件?** 若是,须确定软件安全等级(GB/T 25000.51)以及是否需要网络安全要求。 | 🟡 中 | 功能要求;法规与标准 | 软件需求缺失,GB/T 25000.51 符合性无法保证 | +| **S-08** | **电极接触类型(皮肤/侵入)与接触时间(短暂/长期/永久)是什么?** 影响生物相容性评价范围与测试项目。 | 🟡 中 | 安全与风险 | 生物相容性测试项目无法确定 | +| **S-09** | **设计开发计划节点与型检预计送检时间?** 影响资源配置与里程碑设定。 | 🟡 中 | 追溯表(下游) | 设计开发计划无进度约束输入 | +| **S-10** | **设备预期使用寿命与保修期?** 影响 MTBF/MTTF 假设与标签声明。 | 🟡 中 | 性能要求 | 可靠性指标缺失,使用寿命声明无依据 | + +--- + +## 十、签署 + +| 角色 | 姓名 | 结论 | 日期 | +|---|---|---|---| +| 编制(研发设计控制负责人) | — | 已完成 DHF 终审,整合前序专员产出 | 2026-09-17 | +| 审核 | — | | | +| 批准 | — | | | + +> **注**:依据本规格书「DHF 设计控制纪律」,签字须由具备相应授权的人员在缺口确认完成后补充填写。本版(A版)为初始发行,缺口关闭后应更新版本。 + +--- + +## 附录 A:工程师技术评审纪要(引用自 02_engineer/output.md) + +### A.1 技术路线分析 + +**设备类型判定**:基于材料描述「脉冲刺激、强度可调、会话计时、紧急停止」,结合频率 1–100 Hz、脉宽 50–500 µs 范围,本产品属于经皮神经电刺激(TENS)类设备(符合 YY 9706.210-2021 范围定义)(分析判断,无直接条文依据),最可能的预期用途场景为镇痛或肌肉刺激。 + +**输出模式**:材料未明确恒流/恒压输出模式。恒流模式对组织阻抗变化有自适应性,是更安全的 TENS 设备方案,但成本较高;恒压模式成本低但安全性略弱。若用户无明确要求,推荐优先考虑恒流模式,并满足 YY 9706.210 第 6.8 条的输出限制要求。 + +### A.2 工程化差距摘要 + +| 事项 | 现状 | 目标 | 差距 | 内部/外部能力 | 工作量量级 | +|---|---|---|---|---|---| +| 强度上限确定 | 未提供 | 明确电流/电压上限值 | 需用户确认 + 标准比对 | 用户确认 + 研发内部设计 | 1–2 周 | +| 危害分析开展 | ISO 14971 框架已引用,分析未开展 | 完成危害清单与风险控制措施 | 需专业风险管理工程师 | 内部或外部风险管理咨询 | 4–8 周 | +| 型检方案编制 | 材料列有 GB 9706.1/YY 9706.102 | 完整检测项目清单、样品数量、送检机构 | 需 GB 9706.1-2022 与 YY 9706.210 比对 | 型检机构 + 研发内部 | 2–4 周 | +| 软件需求定义 | 未提及 | 嵌入式软件需求文档、等级确认 | 需确认是否含软件 | 研发内部 | 2–3 周 | +| EMC 版次确认 | YY 9706.102 版次不明 | NMPA 接受的最新有效版本 | 需法规/注册确认 | 法规/注册团队 | 1–2 周 | +| 临床评价范围 | 预期用途待确认 | 临床评价报告(CER) | 需预期用途闭环 + 文献调研 | 临床评价机构 | 8–16 周 | + +### A.3 对前序的验证 + +01_organize 产出的事实清单(F-01~F-14)与缺口清单(G-01~G-11)准确、可追溯,已被本规格书完整引用。本规格书验证了以下上游判断: + +- G-01(预期用途无正式陈述):确认,标记为 S-01。 +- G-02(刺激强度上限缺失):确认,标记为 S-02,且该缺口同时阻断安全章节 DI-S-001 参数化。 +- G-05(使用环境边界细化):确认,标记为 S-05/S-06,EMC 版次额外增加 DI-R-002 风险。 +- G-11(IEC 60601-1-2 版次):扩展为 S-06,且发现 NMPA 可能存在第 3 版与第 4 版的窗口期问题。 + +无前序与本阶段之间的矛盾。已批准文档(project.md)锁定的核心前提未被本阶段推翻。 + +--- + +## 附录 B:引用文件清单 + +| 编号 | 文件名称 | 版本/日期 | 来源 | +|---|---|---|---| +| 1 | design_input_brief.md | — | 用户上传材料 | +| 2 | upload_material_design_input_brief.md.md | — | 用户上传材料 | +| 3 | project.md | — | 项目上下文 | +| 4 | blackboard.json | 2026-09-17T09:07:08Z | 前序专员产出 | +| 5 | 02_engineer/output.md | 2026-09-17 | 前序工程师产出 | +| 6 | GB 9706.1-2022 | 2022 | 国家标准 | +| 7 | YY 9706.102-2021 | 2021 | 行业标准 | +| 8 | YY 9706.210-2021 | 2021 | 行业标准 | +| 9 | ISO 14971:2019 | 2019 | 国际标准 | +| 10 | GB/T 25000.51-2016 | 2016 | 国家标准 | +| 11 | YY 9706.111-2021 | 2021 | 行业标准 | + +--- + +**说明**:本文档由研发小队在任务快照上生成,属于设计历史记录。后续补充的材料不会改变本次内容,须通过变更控制流程更新。 diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/rdev-leader-AGENTS.md b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/rdev-leader-AGENTS.md new file mode 100644 index 00000000..b042d930 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/rdev-leader-AGENTS.md @@ -0,0 +1,78 @@ +## 角色 + +你是研发/设计控制小队的负责人(花名册名称:研发设计控制负责人)。按 ISO 13485 把本阶段做成可追溯的 DHF 记录。你是用户与小队之间的唯一接口:专员向你汇报,只有你对用户说话、提交阶段文档。 + +你的价值不在于自己写长文,而在于把本阶段设计控制要求变成可验收的任务,审核专员产出,整合成一份可提交的 Markdown 终稿。结论短、论证完整:卡片可以短,DHF 文档不能短。 + +**明确边界**:不做报价核算与商务承诺,不写商务对接口径。 + +## 汇报纪律 + +- 只有你可以把成果交给用户(通过系统落文档)。不要把未审核的专员原文直接当终稿。 +- 需要用户决策的事项一律上升,不要代用户拍板。 +- 专员产出不合格时退回说明差距;系统按剧本执行,你负责审核与整合。 + +## 本阶段你要做的(DHF 终审) + +1. 用一句话回述本阶段交付物及其 DHF 归属。 +2. 阅读快照、材料文本、前序文档和各专员 `output.md`。 +3. 按本阶段 RD 模板整合终稿,结论先行;与前序已批准文件保持一致。 +4. **追溯表必填核查**:本文件 ID、上游输入、下游验证/确认;未知项写入「待确认」而非留空。 +5. **不适用理由完整性**:声明不适用时须写完整理由,禁止空壳「不适用」。 +6. 缺信息标「待确认」,**禁止编造**试验数据、标准号、URL、签字、附件正文。 +7. 按 TASK.md 指定的交付文件落盘:终稿步写 `output.md`;若本步是「审核撰写计划」(review_plan),只写 `review_notes.md`,**禁止**把审核意见写入或覆盖 `output.md`。 +8. 专员已标注的出处必须保留;你整合时把能溯源的句子标上〔…〕,无依据的分析不要删,也不要补造引用。 + +## 汇报格式(终稿 output.md 开头;计划审核则写在 review_notes.md) + +**注意**:你整合生成的终稿文档结构必须严格遵循 `template.md` 的所有章节结构,不得自行替换为审阅报告结构!你的审阅和把关成果体现为:在保持 `template.md` 章节骨架(如 ## 结论、## 适用性、专业正文各节、## 追溯、## 待确认清单、## 签署 等)的基础上,将专员的草稿进行逻辑润色、出处溯源和终审定稿输出。 + +**待确认清单**:在模板对应章节中集中列出文中所有「待确认」。 + + +## 写作质量 + +模板是章节骨架,不是篇幅上限。禁止把模板括号提示原样留下。卡片摘要可以短;阶段文档必须论证完整。结论短、论证完整。 + +### 详细 + +- 每一节至少包含:结论句 → 表格或列表(可用 Mermaid,图表要有标题) → 解读段落 → 支撑明细或出处。不要通篇只有列表。 +- 数字必须写清口径、假设、来源与日期。没有数字时写「未检索到公开信息」或「材料未提供」,并说明已尝试路径。 +- 表格禁止交空壳:至少填已知行;若确实无数据,用一行写明「为何为空」及待确认项。 +- 专员交给撰写岗的稿件要写完整论据,不要只交标题或提纲。 + +### 逻辑通顺 + +- 结论先行,后文不得与结论打架。写作过程中出现新事实,必须回写结论。 +- 章节按「事实 → 分析 → 对本项目的含义 → 建议或待拍板」推进。 +- 前序已批准文档与本阶段材料冲突时,两个都列出来并标记冲突,不默默取一边。 +- 选项对比用同一套维度(证据、周期、成本量级、风险、适用条件)。术语首次出现先定义。 +- 因果链写清:因 → 果 → 建议。不要跳跃到未交代的前提。 + +### 考虑全面 + +- 每份终稿显式覆盖:适用与不适用、机会与风险、优势与短板、已知与待确认、现在要用户做什么。没有决策则写「无需决策」。 +- 写推荐必须同时写否决或失效条件。 +- 能标出处的句子必须标〔…〕。无直接条文依据的分析保留,并标「(分析判断,无直接条文依据)」。 +- 会议纪要类短文档至少要有一个流程或责任矩阵。 + +### 自检(撰写岗与负责人必做) + +1. 模板中的每个章节是否都写完,没有残留括号提示。 +2. 关键数字、路径、参数前后是否一致,且可追溯。 +3. 文中所有「待确认」是否已在文末清单汇总。 +4. 是否有未标注的推测、疗效宣称或绝对化用语。 +5. 专员已标注的出处是否保留;无依据的分析是否被误删。 + +## DHF 设计控制纪律(研发设计控制流程 rd_* 任务) + +> **分工红线**:模板管结构与占位;overlay/运行时管写作纪律与粒度下限。详见 [08-rdev模板写作规范](../../.doc/system-design/project-workflow/08-rdev模板写作规范.md)。 + +适用于 ISO 13485 设计历史文件(DHF)类受控文档: + +- 模板各章节必须写满;禁止残留括号提示或空表壳。 +- 结论先行:文首给出适用性/通过/不适用结论,后文论证不得与结论矛盾。 +- 追溯表必填:本文件 ID、上游输入、下游验证/确认;未知项写入「待确认」而非留空。 +- 缺项统一标「待确认」,并在文末待确认清单汇总。 +- 严禁编造试验数据、标准号、URL、签字、附件正文;附件清单类只建索引。 +- 声明不适用时须写完整理由(首期若任务在规划期关闭则不生成正文)。 diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/run_s0_rdev_continue.py b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/run_s0_rdev_continue.py new file mode 100644 index 00000000..3442059e --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/run_s0_rdev_continue.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python3 +"""Continue S0.3 from project 6424: activate rdev + PI rd_design_input_spec.""" +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 +PROJECT_ID = int(os.environ.get("PROJECT_ID", "6424")) +TASK_TIMEOUT = int(os.environ.get("TASK_TIMEOUT_SEC", "2400")) +LOG = [] + + +def log(msg): + 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) + t0 = time.time() + 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, int((time.time() - t0) * 1000) + 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, int((time.time() - t0) * 1000) + + +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["user"] + + +def main(): + admin_token, admin = login(os.environ.get("ADMIN_USERNAME", "admin"), os.environ["ADMIN_PASSWORD"]) + admin_id = int(admin["id"]) + reviewer_token, reviewer = login("lizhuguan", "123456") + approver_token, approver = login("wangzong", "123456") + reviewer_id, approver_id = int(reviewer["id"]), int(approver["id"]) + author_id = admin_id + + st, proj, raw, _ = req("GET", f"/api/v1/projects/{PROJECT_ID}", admin_token) + log(f"project lifecycle={proj.get('lifecycle_status')} sel={proj.get('workflow_selection_version')} plan_rev={proj.get('workflow_plan_revision')}") + 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=rdev&version=0", admin_token) + if st != 200: + raise SystemExit(f"default rdev plan: {st} {raw[:800]}") + 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 == "rd_design_input_spec": + dt["enabled"] = True + dt["duties"] = { + "author_user_id": author_id, + "reviewer_user_id": reviewer_id, + "approver_user_id": approver_id, + } + else: + dt["enabled"] = False + dt["duties"] = {} + st, _, raw, _ = req("PUT", f"/api/v1/projects/{PROJECT_ID}/workflow-plan", admin_token, { + "plan": plan, + "expected_plan_revision": plan_rev, + "expected_selection_version": sel_ver, + }) + log(f"save rdev plan http={st}") + if st != 200: + raise SystemExit(raw[:1000]) + st, preview, raw, _ = req("POST", f"/api/v1/projects/{PROJECT_ID}/activation-preview", admin_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", admin_token, { + "confirmation_token": preview["confirmation_token"], + "expected_project_version": preview["expected_project_version"], + "expected_plan_revision": preview["expected_plan_revision"], + }) + log(f"activate rdev http={st}") + if st != 200: + raise SystemExit(raw[:1200]) + save_json("activate-rdev.json", activated) + instance = activated.get("instance") or activated + instance_id = int(instance["id"]) + + # Advance empty stages until RD03 + stage_keys = [] + for s in plan.get("stages") or []: + sk = s.get("stage_key") or s.get("key") + if sk: + stage_keys.append(sk) + for sk in stage_keys: + if sk == "RD03_design_input": + break + detail = req("GET", f"/api/v1/workflow-instances/{instance_id}", admin_token)[1] + inst = (detail or {}).get("instance") or detail or {} + rev = inst.get("config_revision") + st, _, raw, ms = req("POST", f"/api/v1/workflow-instances/{instance_id}/stages/{sk}/advance", admin_token, { + "stage_key": sk, "expected_config_revision": rev, + }) + log(f"advance {sk}: http={st} ms={ms}") + if st != 200: + log(f"advance stop at {sk}: {raw[:400]}") + break + + fields = { + "customer_name": "水木东方测试客户", + "device_type": "二类有源医疗器械(神经刺激)", + "intended_use": "无创神经电刺激辅助改善目标症状", + "target_market": "中国 NMPA", + } + sess = f"sess-rdev-s0-p{PROJECT_ID}-rd_design_input_spec" + req("POST", "/api/v1/chat/sessions", admin_token, { + "session_id": sess, "title": "rd_design_input_spec", "user_id": author_id, "project_id": PROJECT_ID, + }) + body = { + "session_id": sess, + "client_turn_id": f"rdev-s0-di-{int(time.time())}", + "user_message": "请编制《设计输入规格书》,按模板五节专业结构写满,不做疗效宣称。", + "task_key": "rd_design_input_spec", + "project_name": proj.get("name"), + "customer_name": fields["customer_name"], + "device_type": fields["device_type"], + "intended_use": fields["intended_use"], + "target_market": fields["target_market"], + "fields": fields, + "backend": "pi-agent", + "project_id": PROJECT_ID, + "author_id": author_id, + "reviewer_id": reviewer_id, + "approver_id": approver_id, + "materials": [{ + "filename": "design_input_brief.md", + "content": b64( + "# 设计输入摸底\n\n" + "## 功能\n脉冲刺激、强度可调、会话计时、紧急停止。\n" + "## 性能\n刺激频率 1-100Hz,脉宽 50-500us,强度步进待确认。\n" + "## 接口与环境\nUSB 充电;工作温度 5-40C;电极接口待确认。\n" + "## 安全\n过流保护、电极脱落检测、风险输入引用 ISO 14971。\n" + "## 法规\nGB 9706.1、YY 9706.102、网络安全指导原则(非强制)。\n" + ), + }], + } + log("PI start rd_design_input_spec") + st, created, raw, _ = req("POST", "/api/v1/tasks/runs", admin_token, body, timeout=60) + if st not in (200, 202) or not created or not created.get("run_id"): + raise SystemExit(f"create run: {st} {raw[:1000]}") + run_id = created["run_id"] + final = None + t0 = time.time() + while time.time() - t0 < TASK_TIMEOUT: + gs, gb, _, _ = req("GET", f"/api/v1/tasks/runs/{run_id}", admin_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"): + final = gb + log(f"PI done status={status} elapsed={int(time.time()-t0)}s err={gb.get('ErrorMessage') or gb.get('error') or ''}") + break + if int(time.time() - t0) % 30 < 12: + log(f"PI poll status={status} elapsed={int(time.time()-t0)}s") + time.sleep(10) + if not final: + raise SystemExit("timeout") + save_json("pi-rd_design_input_spec-meta.json", final) + + work = final.get("WorkspaceID") or final.get("work_dir") or final.get("workspace_id") or "" + host = work.replace("/app/data/", "/home/weichen/projects/Agent-System/data/dev/") + md = "" + agents = None + for root in (Path(host), Path(work)): + if not root.exists(): + continue + for p in [root / "output.md", *sorted(root.rglob("output.md"))]: + if p.is_file() and p.stat().st_size > len(md): + md = p.read_text(encoding="utf-8") + for rel in ("tasks/04_review/AGENTS.md", "tasks/05_review/AGENTS.md"): + p = root / rel + if p.is_file(): + agents = p + break + if agents is None: + for p in root.rglob("AGENTS.md"): + if "review" in str(p): + agents = p + break + if md: + (ASSETS / "rd_design_input_spec-final.md").write_text(md, encoding="utf-8") + if agents: + (ASSETS / "rdev-leader-AGENTS.md").write_text(agents.read_text(encoding="utf-8"), encoding="utf-8") + log(f"archived AGENTS from {agents}") + + st, doc, raw, _ = req("GET", f"/api/v1/docgov/document?doc_id=doc_proj{PROJECT_ID}_rd_design_input_spec", admin_token) + save_json("rd_design_input_spec-docgov.json", doc if doc else {"http": st, "raw": raw[:1000]}) + + summary = { + "project_id": PROJECT_ID, + "rdev_instance_id": instance_id, + "run_id": run_id, + "run_status": final.get("Status") or final.get("status"), + "di_chars": len(md), + "has_five_sections": all(h in md for h in ("## 功能要求", "## 性能要求", "## 接口与环境要求", "## 安全与风险输入", "## 法规与标准符合性")), + "no_placeholder": "按本阶段专业结构写" not in md, + "agents_ok": bool(agents) and ("设计控制" in agents.read_text(encoding="utf-8")), + "no_business_in_agents": bool(agents) and ("商务对接负责人" not in agents.read_text(encoding="utf-8")) and ("CDO" not in agents.read_text(encoding="utf-8")), + "stage_from_docgov": (doc or {}).get("stage") or (doc or {}).get("stage_key"), + "work_dir": host or work, + } + save_json("summary-rdev.json", summary) + (ASSETS / "console-rdev.log").write_text("\n".join(LOG) + "\n", encoding="utf-8") + print(json.dumps(summary, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/run_s0_real_pi.py b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/run_s0_real_pi.py new file mode 100644 index 00000000..115fee3a --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/run_s0_real_pi.py @@ -0,0 +1,505 @@ +#!/usr/bin/env python3 +"""S0.3 real-PI sample for rdev template depth (dev :8080 + MiniMax).""" +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 + + +def b64(text: str) -> str: + return base64.b64encode(text.encode("utf-8")).decode("ascii") + +BASE = os.environ.get("BASE_URL", "http://127.0.0.1:8080").rstrip("/") +ASSETS = Path(os.environ.get( + "RDEV_S0_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-s0-{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 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) + t0 = time.time() + 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, int((time.time() - t0) * 1000) + 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, int((time.time() - t0) * 1000) + + +def save_json(name, obj): + path = ASSETS / name + path.write_text(json.dumps(obj, ensure_ascii=False, indent=2), encoding="utf-8") + return path + + +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 for {user}: {st} {raw[:300]}") + return parsed["token"], parsed.get("user") or {} + + +def enable_only(plan: dict, keep: set[str], author: int, reviewer: int, approver: int): + 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, ms = req( + "GET", + f"/api/v1/projects/{project_id}/workflow-plan/default?workflow_key={workflow_key}&version=0", + token, + ) + log(f"default plan {workflow_key}: http={st} ms={ms}") + if st != 200: + raise SystemExit(f"default plan failed: {raw[:800]}") + enable_only(plan, set(keep_keys), author, reviewer, approver) + save_body = { + "plan": plan, + "expected_plan_revision": plan_rev, + "expected_selection_version": sel_ver, + } + st, saved, raw, ms = req("PUT", f"/api/v1/projects/{project_id}/workflow-plan", token, save_body) + log(f"save plan {workflow_key}: http={st} ms={ms}") + if st != 200: + raise SystemExit(f"save plan failed: {raw[:1200]}") + st, preview, raw, ms = req("POST", f"/api/v1/projects/{project_id}/activation-preview", token) + log(f"activation-preview: http={st} ms={ms}") + if st != 200: + raise SystemExit(f"preview failed: {raw[:800]}") + act_body = { + "confirmation_token": preview["confirmation_token"], + "expected_project_version": preview["expected_project_version"], + "expected_plan_revision": preview["expected_plan_revision"], + } + st, activated, raw, ms = req( + "POST", f"/api/v1/projects/{project_id}/workflow-instances/activate", token, act_body + ) + log(f"activate {workflow_key}: http={st} ms={ms}") + if st != 200: + raise SystemExit(f"activate failed: {raw[:1200]}") + save_json(f"activate-{workflow_key}.json", activated) + return activated + + +def run_pi(token, project_id, task_key, fields, author, reviewer, approver, materials=None, session_id=None): + sess = session_id or f"sess-rdev-s0-p{project_id}-{task_key}" + # ensure chat session exists + 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"rdev-s0-{task_key}-{int(time.time())}", + "user_message": f"请编制《{task_key}》受控文档,按模板写满专业章节。", + "task_key": task_key, + "project_name": PROJ_NAME, + "customer_name": fields.get("customer_name", "水木东方测试客户"), + "device_type": fields.get("device_type"), + "intended_use": fields.get("intended_use"), + "target_market": fields.get("target_market"), + "fields": fields, + "backend": "pi-agent", + "project_id": project_id, + "author_id": author, + "reviewer_id": reviewer, + "approver_id": approver, + "materials": materials or [ + { + "filename": "brief.md", + "content": b64("# rdev S0 brief\n\n无创神经刺激器设计输入摸底。\n"), + } + ], + } + log(f"PI async start task={task_key}") + st, parsed, raw, ms = req("POST", "/api/v1/tasks/runs", token, body, timeout=60) + log(f"PI create run task={task_key} http={st} ms={ms}") + if st not in (200, 202) or not parsed or not parsed.get("run_id"): + raise SystemExit(f"create run failed: {st} {(raw or '')[:1500]}") + run_id = parsed["run_id"] + final = None + t0 = time.time() + while time.time() - t0 < TASK_TIMEOUT: + gs, gb, graw, _ = 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"): + final = gb + err = gb.get("error") or gb.get("ErrorMessage") or "" + log(f"PI poll task={task_key} status={status} elapsed={int(time.time()-t0)}s err={err[:120]}") + break + if int(time.time() - t0) % 30 < 12: + log(f"PI poll task={task_key} status={status} elapsed={int(time.time()-t0)}s keys={list(gb.keys())[:8]}") + time.sleep(10) + if final is None: + raise SystemExit(f"PI {task_key} timed out run_id={run_id}") + save_json(f"pi-{task_key}-meta.json", { + "create_http": st, + "run_id": run_id, + "final": final, + "duration_ms": int((time.time() - t0) * 1000), + }) + if final.get("status") != "completed" and final.get("Status") != "completed": + # Soft salvage: PI workspace may have completed while UoW publish failed. + work_dir = final.get("work_dir") or final.get("WorkspaceID") or "" + ws_id = final.get("workspace_id") or "" + soft = { + "success": False, + "work_dir": work_dir, + "workspace_id": ws_id, + "doc_record": final.get("doc_record"), + "primary_artifact": final.get("primary_artifact") or {}, + "run_id": run_id, + "raw_final": final, + } + md = extract_markdown(soft) + if len(md) >= 800: + log(f"PI {task_key} UoW failed but workspace output salvageable chars={len(md)}") + soft["success"] = True + soft["salvaged"] = True + return soft + raise SystemExit( + f"PI {task_key} not completed: {final.get('status') or final.get('Status')} " + f"err={final.get('error') or final.get('ErrorMessage')}" + ) + status = final.get("status") or final.get("Status") + work_dir = final.get("work_dir") or final.get("WorkspaceID") or "" + return { + "success": True, + "work_dir": work_dir, + "workspace_id": final.get("workspace_id") or parsed.get("workspace_id"), + "doc_record": final.get("doc_record"), + "primary_artifact": final.get("primary_artifact") or {}, + "run_id": run_id, + "raw_final": final, + "status": status, + } + + +def extract_markdown(pi_result: dict) -> str: + pa = pi_result.get("primary_artifact") or {} + md = pa.get("markdown_body") or "" + work_dir = pi_result.get("work_dir") or "" + ws_id = pi_result.get("workspace_id") or "" + roots = [] + if work_dir: + roots.append(Path(work_dir)) + if ws_id: + roots.append(Path("/home/weichen/projects/Agent-System/data/dev/workspaces") / ws_id) + roots.append(Path("/home/weichen/projects/Agent-System/data/dev/workspaces/bizdev") / ws_id) + # common patterns + for p in Path("/home/weichen/projects/Agent-System/data/dev/workspaces").rglob(ws_id): + if p.is_dir(): + roots.append(p) + break + for root in roots: + if not root.is_dir(): + continue + candidates = [root / "output.md"] + candidates.extend(sorted(root.rglob("output.md"))) + for p in candidates: + if p.is_file(): + text = p.read_text(encoding="utf-8") + if len(text) > len(md): + md = text + # remember work_dir for agents lookup + if not pi_result.get("work_dir"): + pi_result["work_dir"] = str(root) + return md + + +def find_leader_agents(work_dir: str) -> str | None: + if not work_dir: + return None + root = Path(work_dir) + for rel in ("tasks/04_review/AGENTS.md", "tasks/05_review/AGENTS.md", "tasks/03_review/AGENTS.md"): + p = root / rel + if p.is_file(): + return str(p) + if root.is_dir(): + for p in root.rglob("AGENTS.md"): + if "review" in str(p): + return str(p) + return None + + +def approve_chain(author_token, reviewer_token, approver_token, doc_id, author_id, reviewer_id, approver_id): + st, _, raw, _ = req("POST", "/api/v1/docgov/claim", author_token, { + "doc_id": doc_id, "user_id": author_id, "user_name": "author", + }) + log(f"claim: http={st}") + st, _, raw, _ = req("POST", "/api/v1/docgov/submit-review", author_token, { + "doc_id": doc_id, "author_id": author_id, "note": "S0 auto submit", + }) + log(f"submit-review: http={st}") + if st != 200: + raise SystemExit(f"submit-review failed: {raw[:800]}") + st, _, raw, _ = req("POST", "/api/v1/docgov/review-decision", reviewer_token, { + "doc_id": doc_id, "user_id": reviewer_id, "user_name": "reviewer", + "action": "approve", "comment": "S0 ok", + }) + log(f"review-decision: http={st}") + if st != 200: + raise SystemExit(f"review-decision failed: {raw[:800]}") + st, _, raw, _ = req("POST", "/api/v1/docgov/approver-decision", approver_token, { + "doc_id": doc_id, "user_id": approver_id, "user_name": "approver", + "action": "approve", "comment": "S0 ok", + }) + log(f"approver-decision: http={st}") + if st != 200: + raise SystemExit(f"approver-decision failed: {raw[:800]}") + + +def get_instance(token, instance_id): + st, parsed, raw, _ = req("GET", f"/api/v1/workflow-instances/{instance_id}", token) + if st != 200: + raise SystemExit(f"get instance: {st} {raw[:600]}") + return parsed + + +def advance_stages(token, instance_id, stage_keys: list[str]): + for sk in stage_keys: + detail = get_instance(token, instance_id) + inst = detail.get("instance") or detail + status = (inst.get("status") or "").lower() + if status in ("completed", "complete", "done"): + log(f"instance already {status}") + return detail + rev = inst.get("config_revision") + body = {"stage_key": sk, "expected_config_revision": rev} + st, parsed, raw, ms = req( + "POST", + f"/api/v1/workflow-instances/{instance_id}/stages/{sk}/advance", + token, + body, + ) + log(f"advance {sk}: http={st} ms={ms}") + if st != 200: + save_json(f"advance-fail-{sk}.json", {"http": st, "body": parsed or raw}) + raise SystemExit(f"advance {sk} failed: {raw[:1200]}") + time.sleep(0.3) + return get_instance(token, instance_id) + + +def main(): + admin_user = os.environ.get("ADMIN_USERNAME", "admin") + admin_pass = os.environ["ADMIN_PASSWORD"] + admin_token, admin = login(admin_user, admin_pass) + admin_id = int(admin["id"]) + log(f"admin id={admin_id}") + + # Prefer seeded users for cross-user duty; author always admin to avoid UoW permission denied. + author_token, author_id = admin_token, admin_id + reviewer_token, reviewer_id = admin_token, admin_id + approver_token, approver_id = admin_token, admin_id + for user, pwd, slot in ( + ("lizhuguan", "123456", "reviewer"), + ("wangzong", "123456", "approver"), + ): + try: + tok, u = login(user, pwd) + except SystemExit: + log(f"seed user {user} unavailable; keep admin") + continue + uid = int(u["id"]) + log(f"seed user {user} id={uid}") + if slot == "reviewer": + reviewer_token, reviewer_id = tok, uid + else: + approver_token, approver_id = tok, uid + log(f"duty author=admin({admin_id}) reviewer={reviewer_id} approver={approver_id}") + + st, proj, raw, ms = req( + "POST", + "/api/v1/projects", + admin_token, + { + "name": PROJ_NAME, + "product_domain": "medical_device", + "device_type": "二类有源医疗器械(神经刺激)", + "intended_use": "无创神经电刺激辅助改善目标症状", + "target_market": "中国 NMPA", + "customer_name": "水木东方测试客户", + }, + ) + log(f"create project: http={st} ms={ms}") + if st not in (200, 201): + raise SystemExit(f"create project failed: {raw[:800]}") + project_id = int(proj["id"]) + save_json("project.json", proj) + + # Ensure creator ownership via admin; upsert duty users as members + for uid, role in ((admin_id, "owner"), (author_id, "member"), (reviewer_id, "member"), (approver_id, "member")): + st, _, raw, _ = req( + "POST", f"/api/v1/projects/{project_id}/members", admin_token, + {"user_id": uid, "role": role}, + ) + log(f"member user={uid} role={role} http={st}") + + fields = { + "customer_name": "水木东方测试客户", + "device_type": "二类有源医疗器械(神经刺激)", + "intended_use": "无创神经电刺激辅助改善目标症状", + "target_market": "中国 NMPA", + } + + activated = plan_and_activate( + admin_token, project_id, "main", ["intake"], author_id, reviewer_id, approver_id, + ) + instance = activated.get("instance") or activated + instance_id = int(instance["id"]) + + intake = run_pi(author_token, project_id, "intake", fields, author_id, reviewer_id, approver_id) + intake_md = extract_markdown(intake) + (ASSETS / "intake-final.md").write_text(intake_md, encoding="utf-8") + doc_id = ((intake.get("doc_record") or {}).get("doc_id")) or f"doc_proj{project_id}_intake" + # StageKey regression sample + save_json("intake-doc-id.json", {"doc_id": doc_id}) + + approve_chain( + author_token, reviewer_token, approver_token, doc_id, + author_id, reviewer_id, approver_id, + ) + main_final = advance_stages(admin_token, instance_id, ["V0.1_triage", "V0.5_feasibility", "V1.0_quoting"]) + save_json("main-instance-final.json", main_final) + main_status = ((main_final.get("instance") or main_final).get("status")) + log(f"main final status={main_status}") + + activated2 = plan_and_activate( + admin_token, project_id, "rdev", ["rd_design_input_spec"], + author_id, reviewer_id, approver_id, + ) + instance2 = activated2.get("instance") or activated2 + instance2_id = int(instance2["id"]) + + # Advance empty early stages to RD03 if needed + rdev_stage_order = [] + for s in (activated2.get("plan") or {}).get("stages") or []: + sk = s.get("stage_key") or s.get("key") + if sk: + rdev_stage_order.append(sk) + # fallback known order prefix + if not rdev_stage_order: + rdev_stage_order = [ + "RD01_planning", "RD02_planning_review", "RD03_design_input", + ] + # advance until design input stage is current / reachable + for sk in rdev_stage_order: + if sk == "RD03_design_input": + break + try: + advance_stages(admin_token, instance2_id, [sk]) + except SystemExit as e: + log(f"advance skip/fail {sk}: {e}") + break + + di = run_pi( + author_token, project_id, "rd_design_input_spec", fields, + author_id, reviewer_id, approver_id, + materials=[{ + "filename": "design_input_brief.md", + "content": b64( + "# 设计输入摸底\n\n" + "## 功能\n脉冲刺激、强度可调、会话计时、紧急停止。\n" + "## 性能\n刺激频率 1-100Hz,脉宽 50-500us,强度步进待确认。\n" + "## 接口与环境\nUSB 充电;工作温度 5-40C;电极接口待确认。\n" + "## 安全\n过流保护、电极脱落检测、风险输入引用 ISO 14971。\n" + "## 法规\nGB 9706.1、YY 9706.102、网络安全指导原则(非强制)。\n" + ), + }], + ) + di_md = extract_markdown(di) + (ASSETS / "rd_design_input_spec-final.md").write_text(di_md, encoding="utf-8") + work_dir = di.get("work_dir") or "" + agents_path = find_leader_agents(work_dir) + if agents_path and Path(agents_path).is_file(): + text = Path(agents_path).read_text(encoding="utf-8") + (ASSETS / "rdev-leader-AGENTS.md").write_text(text, encoding="utf-8") + log(f"archived leader AGENTS from {agents_path}") + if "设计控制" not in text: + log("WARN: leader AGENTS missing 设计控制") + if "商务对接负责人" in text or "CDO" in text: + log("WARN: leader AGENTS still has business tone") + else: + log("WARN: leader AGENTS.md not found") + + st, docs, raw, _ = req("GET", f"/api/v1/projects/{project_id}/documents", admin_token) + save_json("documents.json", docs if docs is not None else {"raw": raw[:2000]}) + # try document detail for stage key + st, doc_detail, raw, _ = req("GET", f"/api/v1/docgov/document?doc_id=doc_proj{project_id}_rd_design_input_spec", admin_token) + save_json("rd_design_input_spec-docgov.json", doc_detail if doc_detail is not None else {"http": st, "raw": raw[:1000]}) + + (ASSETS / "console.log").write_text("\n".join(LOG) + "\n", encoding="utf-8") + summary = { + "project_id": project_id, + "project_name": PROJ_NAME, + "main_instance_id": instance_id, + "main_status": main_status, + "rdev_instance_id": instance2_id, + "intake_chars": len(intake_md), + "di_chars": len(di_md), + "agents_path": agents_path, + "work_dir": work_dir, + "has_five_sections": all(h in di_md for h in ("## 功能要求", "## 性能要求", "## 接口与环境要求", "## 安全与风险输入", "## 法规与标准符合性")), + "no_placeholder": "按本阶段专业结构写" not in di_md, + "no_business_tone": ("商务对接负责人" not in di_md) and ("CDO" not in di_md), + } + save_json("summary.json", summary) + log(f"DONE {json.dumps(summary, ensure_ascii=False)}") + print(json.dumps(summary, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/save-rdev-plan-error.json b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/save-rdev-plan-error.json new file mode 100644 index 00000000..fd696a50 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/save-rdev-plan-error.json @@ -0,0 +1 @@ +{"code":"INTERNAL","message":"请求无法完成","request_id":"req_cdebce820010fd8b","error":"INTERNAL"} diff --git a/.doc/test-reports/assets/2026-09-17-rdev-template-depth/summary-rdev.json b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/summary-rdev.json new file mode 100644 index 00000000..c228b3f3 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-17-rdev-template-depth/summary-rdev.json @@ -0,0 +1,18 @@ +{ + "main_project_id": 6424, + "rdev_project_id": 6425, + "main_intake_run_id": "run_1789635054471569201", + "main_intake_duration_ms": 220109, + "rdev_run_id": "run_1789635960880707641", + "rdev_status": "completed", + "workspace": "/app/data/workspaces/bizdev/rd_design_input_spec_1789635960900711737", + "work_dir": "/home/weichen/projects/Agent-System/data/dev/workspaces/bizdev/rd_design_input_spec_1789635960900711737", + "di_chars": 15988, + "stage": "RD03_design_input", + "has_five_sections": true, + "no_placeholder": true, + "agents_ok": true, + "no_business_in_agents": true, + "no_business_in_final": true, + "duration_wall": "09:06:00Z–review output 09:11 (~5min squad); run status=completed" +} \ No newline at end of file diff --git a/configs/agents/rdev_leader.md b/configs/agents/rdev_leader.md new file mode 100644 index 00000000..b55a5fc3 --- /dev/null +++ b/configs/agents/rdev_leader.md @@ -0,0 +1,30 @@ +## 角色 + +你是研发/设计控制小队的负责人(花名册名称:研发设计控制负责人)。按 ISO 13485 把本阶段做成可追溯的 DHF 记录。你是用户与小队之间的唯一接口:专员向你汇报,只有你对用户说话、提交阶段文档。 + +你的价值不在于自己写长文,而在于把本阶段设计控制要求变成可验收的任务,审核专员产出,整合成一份可提交的 Markdown 终稿。结论短、论证完整:卡片可以短,DHF 文档不能短。 + +**明确边界**:不做报价核算与商务承诺,不写商务对接口径。 + +## 汇报纪律 + +- 只有你可以把成果交给用户(通过系统落文档)。不要把未审核的专员原文直接当终稿。 +- 需要用户决策的事项一律上升,不要代用户拍板。 +- 专员产出不合格时退回说明差距;系统按剧本执行,你负责审核与整合。 + +## 本阶段你要做的(DHF 终审) + +1. 用一句话回述本阶段交付物及其 DHF 归属。 +2. 阅读快照、材料文本、前序文档和各专员 `output.md`。 +3. 按本阶段 RD 模板整合终稿,结论先行;与前序已批准文件保持一致。 +4. **追溯表必填核查**:本文件 ID、上游输入、下游验证/确认;未知项写入「待确认」而非留空。 +5. **不适用理由完整性**:声明不适用时须写完整理由,禁止空壳「不适用」。 +6. 缺信息标「待确认」,**禁止编造**试验数据、标准号、URL、签字、附件正文。 +7. 按 TASK.md 指定的交付文件落盘:终稿步写 `output.md`;若本步是「审核撰写计划」(review_plan),只写 `review_notes.md`,**禁止**把审核意见写入或覆盖 `output.md`。 +8. 专员已标注的出处必须保留;你整合时把能溯源的句子标上〔…〕,无依据的分析不要删,也不要补造引用。 + +## 汇报格式(终稿 output.md 开头;计划审核则写在 review_notes.md) + +**注意**:你整合生成的终稿文档结构必须严格遵循 `template.md` 的所有章节结构,不得自行替换为审阅报告结构!你的审阅和把关成果体现为:在保持 `template.md` 章节骨架(如 ## 结论、## 适用性、专业正文各节、## 追溯、## 待确认清单、## 签署 等)的基础上,将专员的草稿进行逻辑润色、出处溯源和终审定稿输出。 + +**待确认清单**:在模板对应章节中集中列出文中所有「待确认」。 diff --git a/configs/shared/writing.md b/configs/shared/writing.md index ded153be..4ff87e98 100644 --- a/configs/shared/writing.md +++ b/configs/shared/writing.md @@ -34,6 +34,8 @@ ## DHF 设计控制纪律(研发设计控制流程 rd_* 任务) +> **分工红线**:模板管结构与占位;overlay/运行时管写作纪律与粒度下限。详见 [08-rdev模板写作规范](../../.doc/system-design/project-workflow/08-rdev模板写作规范.md)。 + 适用于 ISO 13485 设计历史文件(DHF)类受控文档: - 模板各章节必须写满;禁止残留括号提示或空表壳。 diff --git a/internal/squad/rdev_leader_prompt_test.go b/internal/squad/rdev_leader_prompt_test.go new file mode 100644 index 00000000..a7e01cbb --- /dev/null +++ b/internal/squad/rdev_leader_prompt_test.go @@ -0,0 +1,73 @@ +package squad_test + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "chat-agent-system/internal/squad" +) + +func TestRDevLeaderPrompt_UsesDesignControlNotBusiness(t *testing.T) { + tmpDir := t.TempDir() + engine := squad.NewWorkspaceEngine() + + ws, err := engine.PrepareWorkspace(squad.WorkspacePrepareRequest{ + WorkDir: filepath.Join(tmpDir, "rd_design_input_spec"), + TaskKey: "rd_design_input_spec", + StageTitle: "设计输入规格书", + ProjectName: "rdev-s0-prompt", + Backend: "stub", + }) + if err != nil { + t.Fatalf("PrepareWorkspace rd_design_input_spec: %v", err) + } + + leaderAgents := filepath.Join(ws.WorkDir, "tasks", "04_review", "AGENTS.md") + body, err := os.ReadFile(leaderAgents) + if err != nil { + t.Fatalf("read leader AGENTS.md: %v", err) + } + text := string(body) + if !strings.Contains(text, "设计控制") { + t.Fatalf("rdev leader AGENTS.md must mention 设计控制; got snippet:\n%s", truncate(text, 400)) + } + for _, banned := range []string{"商务对接负责人", "CDO"} { + if strings.Contains(text, banned) { + t.Fatalf("rdev leader AGENTS.md must not contain %q", banned) + } + } +} + +func TestIntakeLeaderPrompt_StillBusiness(t *testing.T) { + tmpDir := t.TempDir() + engine := squad.NewWorkspaceEngine() + + ws, err := engine.PrepareWorkspace(squad.WorkspacePrepareRequest{ + WorkDir: filepath.Join(tmpDir, "intake"), + TaskKey: "intake", + StageTitle: "用户初始需求收集表", + ProjectName: "intake-prompt-regression", + Backend: "stub", + }) + if err != nil { + t.Fatalf("PrepareWorkspace intake: %v", err) + } + + leaderAgents := filepath.Join(ws.WorkDir, "tasks", "03_review", "AGENTS.md") + body, err := os.ReadFile(leaderAgents) + if err != nil { + t.Fatalf("read intake leader AGENTS.md: %v", err) + } + if !strings.Contains(string(body), "商务对接负责人") { + t.Fatalf("intake leader AGENTS.md must retain 商务对接负责人") + } +} + +func truncate(s string, n int) string { + if len(s) <= n { + return s + } + return s[:n] + "..." +} diff --git a/internal/squad/rdev_steps.go b/internal/squad/rdev_steps.go index f4be2989..fdf14beb 100644 --- a/internal/squad/rdev_steps.go +++ b/internal/squad/rdev_steps.go @@ -91,6 +91,7 @@ func rdevLeaderAgent() AgentSpec { Model: "claude-3-7-sonnet", Tools: []string{"read", "write", "edit"}, BashPermission: "deny", + InstructionsFile: "configs/agents/rdev_leader.md", Responsibilities: []string{"DHF 完整性终审", "不适用理由审核", "禁止编造检查"}, ForbiddenActions: []string{"严禁代签", "严禁伪造附件内容"}, } diff --git a/internal/squad/workspace.go b/internal/squad/workspace.go index b2d951dc..37792803 100644 --- a/internal/squad/workspace.go +++ b/internal/squad/workspace.go @@ -468,13 +468,20 @@ func (e *WorkspaceEngine) buildSubWorkspaces(workDir string, wf WorkflowPlan, sq return err } - // 1. 生成 AGENTS.md + // 1. 生成 AGENTS.md:优先 AgentSpec.InstructionsFile,再按角色名回落,再 inline 渲染 var agentsBuilder strings.Builder - inst, err := template.GetAgentInstruction(step.Role) - if err == nil { + spec := agentMap[step.Role] + var inst string + var err error + if file := strings.TrimSpace(spec.InstructionsFile); file != "" { + inst, err = template.GetAgentInstructionFile(file) + } + if err != nil || strings.TrimSpace(inst) == "" { + inst, err = template.GetAgentInstruction(step.Role) + } + if err == nil && strings.TrimSpace(inst) != "" { agentsBuilder.WriteString(inst) } else { - spec := agentMap[step.Role] agentsBuilder.WriteString(fmt.Sprintf("# 角色: %s (%s)\n\n", spec.Name, spec.Role)) if len(spec.Responsibilities) > 0 { agentsBuilder.WriteString("## 核心职责\n") diff --git a/internal/template/loader.go b/internal/template/loader.go index 1b93e5d6..f68f8292 100644 --- a/internal/template/loader.go +++ b/internal/template/loader.go @@ -56,11 +56,27 @@ func GetDocTemplate(name string) (string, error) { func GetAgentInstruction(role string) (string, error) { role = strings.TrimSuffix(role, ".md") + if role == "" || strings.Contains(role, "..") || strings.ContainsAny(role, `/\`) { + return "", fmt.Errorf("read agent instruction: invalid role %q", role) + } + return GetAgentInstructionFile(filepath.Join("configs", "agents", role+".md")) +} + +// GetAgentInstructionFile 读取 configs/agents/ 下指定相对路径的指令文件, +// 并自动追加 configs/shared/writing.md。rel 必须落在 configs/agents/ 内,拒绝 ".."。 +func GetAgentInstructionFile(rel string) (string, error) { + rel = filepath.ToSlash(strings.TrimSpace(rel)) + if rel == "" || strings.Contains(rel, "..") { + return "", fmt.Errorf("read agent instruction file: invalid path %q", rel) + } + if !strings.HasPrefix(rel, "configs/agents/") { + return "", fmt.Errorf("read agent instruction file: must be under configs/agents/: %q", rel) + } root := findProjectRoot() - path := filepath.Join(root, "configs", "agents", role+".md") + path := filepath.Join(root, filepath.FromSlash(rel)) b, err := os.ReadFile(path) if err != nil { - return "", fmt.Errorf("read agent instruction %s: %w", role, err) + return "", fmt.Errorf("read agent instruction file %s: %w", rel, err) } inst := string(b) diff --git a/internal/workflowdef/rdev_template_lint_test.go b/internal/workflowdef/rdev_template_lint_test.go new file mode 100644 index 00000000..cdafe0c4 --- /dev/null +++ b/internal/workflowdef/rdev_template_lint_test.go @@ -0,0 +1,63 @@ +package workflowdef + +import ( + "os" + "path/filepath" + "runtime" + "strings" + "testing" +) + +// rdevTemplateDepthAllowlist 已补强模板;随 S0/S1 批次增长。 +var rdevTemplateDepthAllowlist = []string{ + "rd_design_input_spec", + "rd_proposal", + "rd_design_input_list", + "rd_system_design", + "rd_regs_stds", + "rd_adverse_events", + "rd_sw_plan", + "rd_sw_reqs", + "rd_sw_config", + "rd_risk_plan", + "rd_design_plan", + "rd_user_needs", + "rd_hazard_analysis", + "rd_system_reqs", +} + +func TestRDevTemplateDepthLint(t *testing.T) { + _, thisFile, _, _ := runtime.Caller(0) + repoRoot := filepath.Clean(filepath.Join(filepath.Dir(thisFile), "../..")) + templatesDir := filepath.Join(repoRoot, "templates", "docs") + + for _, key := range rdevTemplateDepthAllowlist { + path := filepath.Join(templatesDir, key+".md") + b, err := os.ReadFile(path) + if err != nil { + t.Fatalf("%s: read: %v", key, err) + } + body := string(b) + if strings.Contains(body, "按本阶段专业结构写") { + t.Errorf("%s: still contains generic placeholder 「按本阶段专业结构写」", key) + } + headingCount := 0 + for _, line := range strings.Split(body, "\n") { + if strings.HasPrefix(line, "## ") { + headingCount++ + } + } + if headingCount < 4 { + t.Errorf("%s: want >=4 ## headings, got %d", key, headingCount) + } + if !strings.Contains(body, "| RD-") { + t.Errorf("%s: missing traceability row with | RD-", key) + } + if !strings.Contains(body, "## 待确认清单") { + t.Errorf("%s: missing ## 待确认清单", key) + } + if !strings.Contains(body, "## 签署") { + t.Errorf("%s: missing ## 签署", key) + } + } +} diff --git a/templates/docs/rd_adverse_events.md b/templates/docs/rd_adverse_events.md index 8d8eb7b9..d04867da 100644 --- a/templates/docs/rd_adverse_events.md +++ b/templates/docs/rd_adverse_events.md @@ -10,16 +10,42 @@ ## 结论 -(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) +(一句话:同类产品主要不良事件模式及对本项目设计输入的含义。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) ## 适用性 - 适用 / 不适用:{{applicability}} - 不适用理由:{{na_rationale}} -## 同类产品不良事件信息正文 +## 检索范围与方法 -(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。) +(写满四段式。数据库/时间窗/关键词/产品对照范围;未检索到须说明已尝试路径。禁止编造 URL 与事件编号。) + +| 项 | 内容 | +| --- | --- | +| 数据源 | 待确认 | +| 时间窗 | 待确认 | +| 关键词/产品范围 | 待确认 | + +## 不良事件摘要表 + +(写满四段式。按模式归类;无公开信息写「未检索到公开信息」。) + +| 事件模式 | 典型表现 | 频次/量级(若可知) | 出处 | +| --- | --- | --- | --- | +| 待确认 | 待确认 | 待确认 | 待确认 | + +## 对本项目的设计含义 + +(写满四段式。每条事件模式对应设计输入/风险控制/标签或培训含义。) + +| 事件模式 | 设计输入含义 | 风险控制线索 | 是否已纳入 DI/风险 | +| --- | --- | --- | --- | +| 待确认 | 待确认 | 待确认 | 待确认 | + +## 信息局限与后续监视 + +(写满四段式。数据局限、需窗口核实项、上市后监视建议。) ## 追溯 diff --git a/templates/docs/rd_design_input_list.md b/templates/docs/rd_design_input_list.md index cff0ecb9..4974fdac 100644 --- a/templates/docs/rd_design_input_list.md +++ b/templates/docs/rd_design_input_list.md @@ -10,16 +10,48 @@ ## 结论 -(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) +(一句话:设计输入条目是否齐套、缺口是否已识别。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) ## 适用性 - 适用 / 不适用:{{applicability}} - 不适用理由:{{na_rationale}} -## 设计输入清单正文 +## 输入来源与分类 -(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。) +(写满四段式。说明输入来自用户需求、法规标准、风险、既往产品经验等;分类口径写清。) + +| 分类 | 说明 | 主要来源文档 | +| --- | --- | --- | +| 功能/性能 | 待确认 | 待确认 | +| 法规/标准 | 待确认 | 待确认 | +| 安全/风险 | 待确认 | 待确认 | + +## 设计输入条目表 + +(写满四段式。每条原子化;状态用「已收录/待确认/不适用」。禁止空表。) + +| 输入 ID | 陈述摘要 | 分类 | 来源 | 状态 | 关联规格书条款 | +| --- | --- | --- | --- | --- | --- | +| DI-001 | 待确认 | 待确认 | 待确认 | 待确认 | RD-DI-SPEC | + +## 缺口与冲突 + +(写满四段式。列出缺失输入、相互冲突输入及处理建议;无冲突写「当前未识别冲突」。) + +| 缺口/冲突 | 影响阶段 | 建议动作 | 责任方 | +| --- | --- | --- | --- | +| 待确认 | 待确认 | 待确认 | 待确认 | + +## 齐套性检查 + +(写满四段式。对照设计输入规格书、用户需求、法规清单做齐套结论。) + +| 检查项 | 结果 | 说明 | +| --- | --- | --- | +| 与 RD-DI-SPEC 对齐 | 待确认 | 待确认 | +| 与 RD-UN / RD-SR 对齐 | 待确认 | 待确认 | +| 法规输入已覆盖 | 待确认 | 待确认 | ## 追溯 diff --git a/templates/docs/rd_design_input_spec.md b/templates/docs/rd_design_input_spec.md index 1730887e..e1a14df7 100644 --- a/templates/docs/rd_design_input_spec.md +++ b/templates/docs/rd_design_input_spec.md @@ -10,16 +10,52 @@ ## 结论 -(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) +(一句话概括本规格书覆盖的功能/性能/接口/安全/法规输入是否齐备。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) ## 适用性 - 适用 / 不适用:{{applicability}} - 不适用理由:{{na_rationale}} -## 设计输入规格书正文 +## 功能要求 -(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。) +(写满:结论句 → 表格或列表 → 解读 → 出处。覆盖预期用途相关的核心功能、操作流程与用户角色。缺项写「待确认」。不做疗效宣称。禁止用省略套话跳过本节。) + +| ID | 功能陈述 | 优先级 | 来源 | 验证方式 | +| --- | --- | --- | --- | --- | +| DI-F-001 | 待确认 | 待确认 | 待确认 | 待确认 | + +## 性能要求 + +(写满四段式。覆盖关键性能指标、量程、精度、响应时间、可靠性指标及测量条件。未知写「待确认」并说明口径。) + +| ID | 性能指标 | 目标值/范围 | 测量条件 | 来源 | +| --- | --- | --- | --- | --- | +| DI-P-001 | 待确认 | 待确认 | 待确认 | 待确认 | + +## 接口与环境要求 + +(写满四段式。覆盖人机接口、电气/机械/数据接口、使用环境(温湿度/海拔/电磁)、供电与安装约束。) + +| ID | 接口/环境项 | 要求陈述 | 适用边界 | 来源 | +| --- | --- | --- | --- | --- | +| DI-I-001 | 待确认 | 待确认 | 待确认 | 待确认 | + +## 安全与风险输入 + +(写满四段式。覆盖基本安全、剩余风险可接受性输入、告警/防护、已知危害线索。引用风险管理计划/危害分析时标出处;无则「待确认」。不做疗效宣称。) + +| ID | 安全/风险输入 | 关联危害/控制 | 验证/确认线索 | 来源 | +| --- | --- | --- | --- | --- | +| DI-S-001 | 待确认 | 待确认 | 待确认 | 待确认 | + +## 法规与标准符合性 + +(写满四段式。列出本设计输入须符合的法规、强制性标准与指导原则;指导原则标注「非强制」。条款粒度拆到可验证;禁止合并多条款为一行空话。) + +| ID | 法规/标准 | 适用条款/要点 | 对本输入的含义 | 符合性证据计划 | +| --- | --- | --- | --- | --- | +| DI-R-001 | 待确认 | 待确认 | 待确认 | 待确认 | ## 追溯 diff --git a/templates/docs/rd_design_plan.md b/templates/docs/rd_design_plan.md index b928c596..6e62ea9f 100644 --- a/templates/docs/rd_design_plan.md +++ b/templates/docs/rd_design_plan.md @@ -10,18 +10,42 @@ ## 结论 -(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) +(一句话:DHF 文件计划与阶段节奏是否足以支撑设计控制。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) ## 适用性 - 适用 / 不适用:{{applicability}} - 不适用理由:{{na_rationale}} +## 设计控制策略与阶段划分 + +(写满四段式。策划→输入→输出→验证→确认→转化的阶段目标与门禁。禁止省略套话。) + +| 阶段 | 目标 | 门禁/评审 | 主要输出 | +| --- | --- | --- | --- | +| 01 策划 | 待确认 | 待确认 | 待确认 | +| 03 设计输入 | 待确认 | 待确认 | 待确认 | + ## DHF 文件计划清单 -| 阶段 | 文件 | 记录归属 | 计划完成 | -| --- | --- | --- | --- | -| 策划 | 项目建议书、设计开发计划任务书 | DHF | | +(写满:每行给出计划完成时点与责任角色;未知写「待确认」。) + +| 阶段 | 文件 | 记录归属 | 计划完成 | 责任角色 | +| --- | --- | --- | --- | --- | +| 策划 | 项目建议书、设计开发计划任务书 | DHF | 待确认 | 待确认 | +| 设计输入 | 设计输入清单/规格书、UN/SR、风险相关 | DHF | 待确认 | 待确认 | + +## 资源、接口与依赖 + +(写满四段式。内外部接口、关键依赖、外包边界。) + +| 依赖/接口 | 提供方 | 对本计划影响 | +| --- | --- | --- | +| 待确认 | 待确认 | 待确认 | + +## 进度与变更控制入口 + +(写满四段式。基线计划、变更如何回流到本任务书与 DHF 清单。) ## 追溯 diff --git a/templates/docs/rd_hazard_analysis.md b/templates/docs/rd_hazard_analysis.md index cfc711fb..187d1754 100644 --- a/templates/docs/rd_hazard_analysis.md +++ b/templates/docs/rd_hazard_analysis.md @@ -10,18 +10,46 @@ ## 结论 -(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) +(一句话:主要危害是否已识别、控制与验证线索是否齐全。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) ## 适用性 - 适用 / 不适用:{{applicability}} - 不适用理由:{{na_rationale}} +## 分析范围与方法 + +(写满四段式。分析对象、生命周期阶段、所用方法(如初步危害分析)、参考标准。禁止编造。) + +| 项 | 内容 | +| --- | --- | +| 分析对象 | 待确认 | +| 方法 | 待确认 | +| 参考 | 待确认 | + ## 危害-原因-控制-验证 +(写满:至少一行「待确认」示例;剩余风险不得空白无说明。) + | 危害 | 原因 | 控制措施 | 验证 | 剩余风险 | | --- | --- | --- | --- | --- | -| | | | | 待确认 | +| 待确认 | 待确认 | 待确认 | 待确认 | 待确认 | + +## 风险评价摘要 + +(写满四段式。按可接受准则汇总不可接受项与需进一步控制项。) + +| 危害 ID | 初始风险 | 控制后风险 | 可接受? | 备注 | +| --- | --- | --- | --- | --- | +| 待确认 | 待确认 | 待确认 | 待确认 | 待确认 | + +## 与设计输入的接口 + +(写满四段式。哪些危害驱动了设计输入/软件需求/标签警告。) + +| 危害 | 对应设计输入/需求 | 标签/培训线索 | +| --- | --- | --- | +| 待确认 | 待确认 | 待确认 | ## 追溯 diff --git a/templates/docs/rd_proposal.md b/templates/docs/rd_proposal.md index c346873f..cc5803f2 100644 --- a/templates/docs/rd_proposal.md +++ b/templates/docs/rd_proposal.md @@ -10,16 +10,43 @@ ## 结论 -(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) +(一句话:是否建议立项、产品定位与目标市场是否清晰、主要风险是否可接受。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) ## 适用性 - 适用 / 不适用:{{applicability}} - 不适用理由:{{na_rationale}} -## 项目建议书正文 +## 项目背景与立项依据 -(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。) +(写满:结论句 → 要点列表 → 解读 → 出处。覆盖客户/市场痛点、法规与商业驱动、与公司能力匹配。缺项「待确认」。不做疗效宣称。) + +## 产品定义与范围 + +(写满四段式。覆盖产品名称/类型、预期用途、目标用户与使用场景、明确不在范围内的项。) + +| 项 | 内容 | +| --- | --- | +| 产品类型 | 待确认 | +| 预期用途 | {{intended_use}} | +| 目标市场 | {{target_market}} | +| 范围外 | 待确认 | + +## 目标、里程碑与资源假设 + +(写满四段式。覆盖阶段目标、关键里程碑、人力/外包/关键设备假设;预算与商务报价不在本文展开。) + +| 里程碑 | 计划时点 | 交付物 | 依赖 | +| --- | --- | --- | --- | +| 待确认 | 待确认 | 待确认 | 待确认 | + +## 主要风险与对策概览 + +(写满四段式。技术/法规/供应链/进度风险各至少一条;无则说明「材料未提供」并列入待确认。) + +| 风险 | 影响 | 对策/缓解 | 残余 | +| --- | --- | --- | --- | +| 待确认 | 待确认 | 待确认 | 待确认 | ## 追溯 diff --git a/templates/docs/rd_regs_stds.md b/templates/docs/rd_regs_stds.md index b62d491c..aee26576 100644 --- a/templates/docs/rd_regs_stds.md +++ b/templates/docs/rd_regs_stds.md @@ -10,16 +10,46 @@ ## 结论 -(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) +(一句话:适用法规/标准是否识别完毕、强制与非强制是否区分。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) ## 适用性 - 适用 / 不适用:{{applicability}} - 不适用理由:{{na_rationale}} -## 法规和标准清单正文 +## 监管路径与目标市场 -(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。) +(写满四段式。目标市场/注册路径、器械分类假设、是否含软件/无菌/有源等。字段不足标「待确认」。) + +| 项 | 内容 | +| --- | --- | +| 目标市场 | {{target_market}} | +| 器械分类假设 | 待确认 | +| 监管路径 | 待确认 | + +## 适用法规清单 + +(写满四段式。每条写清效力、对本项目含义;禁止编造标准号。) + +| 法规 | 效力范围 | 对本项目含义 | 证据/出处 | +| --- | --- | --- | --- | +| 待确认 | 待确认 | 待确认 | 待确认 | + +## 适用标准与指导原则 + +(写满四段式。强制标准与指导原则分列;指导原则标注「非强制」。) + +| 标准/指导原则 | 强制/非强制 | 适用条款要点 | 符合性活动 | +| --- | --- | --- | --- | +| 待确认 | 待确认 | 待确认 | 待确认 | + +## 不适用项与理由 + +(写满四段式。明确声明不适用的法规/标准及完整理由;无则写「当前无额外不适用项」。) + +| 法规/标准 | 不适用理由 | +| --- | --- | +| 待确认 | 待确认 | ## 追溯 diff --git a/templates/docs/rd_risk_plan.md b/templates/docs/rd_risk_plan.md index 9bf669f4..edee8e65 100644 --- a/templates/docs/rd_risk_plan.md +++ b/templates/docs/rd_risk_plan.md @@ -10,7 +10,7 @@ ## 结论 -(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) +(一句话:风险管理范围、准则与职责是否明确。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) ## 适用性 @@ -19,7 +19,41 @@ ## 风险管理范围与职责 -(范围、职责、准则、评审节点。缺项写「待确认」。) +(写满四段式。产品范围、生命周期覆盖、角色与职责矩阵。) + +| 角色 | 职责 | 权限边界 | +| --- | --- | --- | +| 风险管理负责人 | 待确认 | 待确认 | +| 设计代表 | 待确认 | 待确认 | +| 法规/质量代表 | 待确认 | 待确认 | + +## 风险可接受准则 + +(写满四段式。严重度/概率等级定义、可接受区域、需受益-风险分析的条件。禁止空壳。) + +| 等级 | 严重度定义 | 概率定义 | 可接受性 | +| --- | --- | --- | --- | +| 待确认 | 待确认 | 待确认 | 待确认 | + +## 活动与交付物 + +(写满四段式。危害分析、风险控制、剩余风险评价、风险报告及与设计评审的衔接。) + +| 活动 | 输入 | 输出 | 责任方 | +| --- | --- | --- | --- | +| 危害分析 | 待确认 | RD-HAZARD 等 | 待确认 | +| 风险控制验证 | 待确认 | 待确认 | 待确认 | +| 风险报告 | 待确认 | 待确认 | 待确认 | + +## 评审节点表 + +(写满四段式。策划/输入/输出/验证/确认各节点的风险管理评审要求。) + +| 节点 | 评审内容 | 通过准则 | 计划时点 | +| --- | --- | --- | --- | +| 设计输入 | 待确认 | 待确认 | 待确认 | +| 设计输出 | 待确认 | 待确认 | 待确认 | +| 验证/确认 | 待确认 | 待确认 | 待确认 | ## 追溯 diff --git a/templates/docs/rd_sw_config.md b/templates/docs/rd_sw_config.md index d8bc101a..62ea10b1 100644 --- a/templates/docs/rd_sw_config.md +++ b/templates/docs/rd_sw_config.md @@ -10,7 +10,7 @@ ## 结论 -(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) +(一句话:配置项识别与维护策略是否足以支撑发布与变更。无软件可声明不适用。信息不足标「待确认」。) 本阶段可声明不适用:无软件成分时可声明不适用。 @@ -19,9 +19,39 @@ - 适用 / 不适用:{{applicability}} - 不适用理由:{{na_rationale}} -## 软件配置及维护计划正文 +## 配置项识别 -(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。) +(写满四段式。源代码、构建脚本、工具链、文档、第三方组件等。) + +| CI 标识 | 描述 | 责任人角色 | 基线节点 | +| --- | --- | --- | --- | +| 待确认 | 待确认 | 待确认 | 待确认 | + +## 版本、基线与发布控制 + +(写满四段式。版本号规则、基线建立时机、发布审批入口。) + +| 活动 | 规则/时机 | 审批 | +| --- | --- | --- | +| 版本号 | 待确认 | 待确认 | +| 基线 | 待确认 | 待确认 | +| 发布 | 待确认 | 待确认 | + +## 变更与维护流程 + +(写满四段式。变更请求、影响分析、回归范围、紧急修复。) + +| 变更类型 | 流程要点 | 回归要求 | +| --- | --- | --- | +| 待确认 | 待确认 | 待确认 | + +## 第三方与工具维护 + +(写满四段式。开源/外购组件清单入口、漏洞响应、工具升级策略。) + +| 组件/工具 | 来源 | 维护策略 | +| --- | --- | --- | +| 待确认 | 待确认 | 待确认 | ## 追溯 diff --git a/templates/docs/rd_sw_plan.md b/templates/docs/rd_sw_plan.md index 5d9733a3..7b521fca 100644 --- a/templates/docs/rd_sw_plan.md +++ b/templates/docs/rd_sw_plan.md @@ -10,7 +10,7 @@ ## 结论 -(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) +(一句话:软件生命周期模型与计划是否适用。无软件成分可声明不适用并写理由。信息不足标「待确认」。) 本阶段可声明不适用:无软件成分时可声明不适用。 @@ -19,9 +19,43 @@ - 适用 / 不适用:{{applicability}} - 不适用理由:{{na_rationale}} -## 软件开发计划正文 +## 开发模型与软件安全分级 -(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。) +(写满四段式。选用的开发生命周期模型、软件安全分类/分级假设及依据。禁止编造标准条款号。) + +| 项 | 内容 | +| --- | --- | +| 开发模型 | 待确认 | +| 软件安全分级假设 | 待确认 | +| 依据 | 待确认 | + +## 生命周期阶段与活动 + +(写满四段式。各阶段活动、输入输出、退出准则。) + +| 阶段 | 主要活动 | 输出 | 退出准则 | +| --- | --- | --- | --- | +| 需求 | 待确认 | 待确认 | 待确认 | +| 设计 | 待确认 | 待确认 | 待确认 | +| 实现 | 待确认 | 待确认 | 待确认 | +| 验证 | 待确认 | 待确认 | 待确认 | +| 发布/维护 | 待确认 | 待确认 | 待确认 | + +## 工具、环境与配置管理 + +(写满四段式。IDE/编译器/CI、配置项范围、基线策略;详见配置及维护计划的交叉引用。) + +| 工具/配置项 | 用途 | 版本/基线策略 | +| --- | --- | --- | +| 待确认 | 待确认 | 待确认 | + +## 验证准则与问题管理 + +(写满四段式。单元/集成/系统测试准入准出、缺陷分级与关闭准则、变更控制入口。) + +| 活动 | 准入 | 准出 | 问题关闭准则 | +| --- | --- | --- | --- | +| 待确认 | 待确认 | 待确认 | 待确认 | ## 追溯 diff --git a/templates/docs/rd_sw_reqs.md b/templates/docs/rd_sw_reqs.md index fee69b5b..35fe57e4 100644 --- a/templates/docs/rd_sw_reqs.md +++ b/templates/docs/rd_sw_reqs.md @@ -3,14 +3,14 @@ - 项目:{{project_name}} - 生成时间:{{generated_at}} - 快照:{{snapshot_id}} -- 文件编号:RD-SW-REQ +- 文件编号:RD-SW-REQS - 记录归属:DHF - 版本:A - 阶段:03 设计输入 ## 结论 -(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) +(一句话:软件需求是否可验证且可追溯到系统/用户需求。无软件可声明不适用。信息不足标「待确认」。) 本阶段可声明不适用:无软件成分时可声明不适用。 @@ -19,15 +19,40 @@ - 适用 / 不适用:{{applicability}} - 不适用理由:{{na_rationale}} -## 软件需求规格书正文 +## 软件范围与上下文 -(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。) +(写满四段式。软件边界、运行平台、与硬件/用户/外部系统的关系。不做疗效宣称。) + +## 功能需求 + +(写满四段式。原子需求;每条可验证。) + +| ID | 需求陈述 | 优先级 | 追溯(SR/UN) | 验证方式 | +| --- | --- | --- | --- | --- | +| SWR-F-001 | 待确认 | 待确认 | 待确认 | 待确认 | + +## 性能、接口与数据需求 + +(写满四段式。性能指标、外部接口、数据保留/精度。) + +| ID | 类型 | 需求陈述 | 目标值/协议 | 验证方式 | +| --- | --- | --- | --- | --- | +| SWR-P-001 | 性能 | 待确认 | 待确认 | 待确认 | +| SWR-I-001 | 接口 | 待确认 | 待确认 | 待确认 | + +## 安全、告警与网络安全需求 + +(写满四段式。安全相关行为、告警、访问控制/网络安全;无则说明并标「待确认」或「不适用理由」。) + +| ID | 需求陈述 | 关联风险/控制 | 验证方式 | +| --- | --- | --- | --- | +| SWR-S-001 | 待确认 | 待确认 | 待确认 | ## 追溯 | 本文件 ID | 上游(输入/需求) | 下游(输出/验证/确认) | | --- | --- | --- | -| RD-SW-REQ | | | +| RD-SW-REQS | | | ## 已有材料摘要 diff --git a/templates/docs/rd_system_design.md b/templates/docs/rd_system_design.md index 52b5c3db..3a23952e 100644 --- a/templates/docs/rd_system_design.md +++ b/templates/docs/rd_system_design.md @@ -10,16 +10,40 @@ ## 结论 -(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) +(一句话:总体架构是否满足设计输入、关键子系统与接口是否明确。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) ## 适用性 - 适用 / 不适用:{{applicability}} - 不适用理由:{{na_rationale}} -## 系统设计方案正文 +## 系统概述与上下文 -(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。) +(写满四段式。产品定位、使用场景、系统边界、与外部环境/用户的关系。可用 Mermaid 上下文图并加标题。不做疗效宣称。) + +## 子系统划分与职责 + +(写满四段式。列出子系统/模块、职责、关键接口归属。) + +| 子系统 | 职责 | 关键接口 | 备注 | +| --- | --- | --- | --- | +| 待确认 | 待确认 | 待确认 | 待确认 | + +## 关键架构决策 + +(写满四段式。技术路线、软硬件划分、安全架构要点、备选方案否决理由。) + +| 决策点 | 选用方案 | 否决方案 | 依据 | +| --- | --- | --- | --- | +| 待确认 | 待确认 | 待确认 | 待确认 | + +## 接口与数据流 + +(写满四段式。人机/电气/数据/网络接口;主数据流与控制流。未知标「待确认」。) + +| 接口 ID | 双方 | 类型 | 协议/约束 | 来源需求 | +| --- | --- | --- | --- | --- | +| IF-001 | 待确认 | 待确认 | 待确认 | 待确认 | ## 追溯 diff --git a/templates/docs/rd_system_reqs.md b/templates/docs/rd_system_reqs.md index 64f6a0e2..f04581c8 100644 --- a/templates/docs/rd_system_reqs.md +++ b/templates/docs/rd_system_reqs.md @@ -7,21 +7,106 @@ - 记录归属:DHF - 版本:A - 阶段:03 设计输入 +- 产品:{{device_type}} +- 预期用途:{{intended_use}} +- 目标市场:{{target_market}} ## 结论 -(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) +(一句话:系统需求是否可验证、可追溯到用户需求与法规输入。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) ## 适用性 - 适用 / 不适用:{{applicability}} - 不适用理由:{{na_rationale}} -## 系统需求 +## 文件简介 + +(本需求规格书针对 {{device_type}} 的市场需求、功能需求与临床/使用流程编写,说明系统需实现的功能与约束。) + +### 目的 + +(明确产品开发需求;作为系统设计、子系统设计、风险分析、临床、测试与验证的依据;信息不足标「待确认」。) + +### 范围 + +(含产品介绍、法规、环境、网络安全、可维护性、性能、可靠性、安全性、易用性等系统需求。) + +### 面向对象 + +(产品策划、系统设计、子系统需求设计、风险分析、临床、测试、验证人员。) + +## 产品介绍 + +### 产品说明 + +(基于材料与字段,标〔材料:文件名〕。不做疗效宣称。) + +### 产品的预期用途 + +{{intended_use}} + +### 产品的结构及组成 + +(结构与组成、关键子系统、能量源、软件/网络安全、人体接触方式等。缺项「待确认」。) + +## 需求输入 + +| 文档编号 | 文件名称 | 版本 | +| --- | --- | --- | +| RD-UN | 用户需求规格书 | 待确认 | +| RD-RISK-PLAN | 风险管理计划 | 待确认 | + +(优先引用 `prior_docs/` 中已批准文档;无 URS 时列出 PIR/技术要求等材料并说明 UR 来源。) + +## 详细需求 + +### 基本法规项 + +| 序号 | 法规项编号 | 软件开发/设计参考的法规文件 | +| --- | --- | --- | +| 1 | 待确认 | 待确认 | + +(来自材料与 `known_standards`;指导原则标注「非强制标准」。) + +### 需求标识 + +**需求分类及标识方法:RX-nnnn** + +| 类别 | 代号 | 含义 | +| --- | --- | --- | +| R | R | 需求(requirement) | +| F | F | 功能需求 | +| P | P | 性能需求 | +| I | I | 接口需求 | +| E | E | 环境需求 | +| U | U | 易用性需求 | +| R | R | 可靠性需求 | +| M | M | 可维护性需求 | +| L | L | 网络安全需求 | +| S | S | 安全需求 | +| O | O | 其他需求 | +| nnnn | 0001… | 流水号 | + +(系统需求 ID 使用 RS/RF/RP 等前缀 + 四位流水号;用户需求 ID 使用 UR-nnnn / UN-nnn。) + +## 需求描述 + +(主表:每条 applies 的系统需求须为原子表述;标准条款须拆至参考文档粒度,禁止合并多条款为一行。) + +| 用户需求ID | 系统需求ID | 系统需求描述 | 备注 | +| --- | --- | --- | --- | +| UR-001 | RS-0001 | 待确认 | 待确认 | + +## 系统需求(摘要表) | ID | 需求陈述 | 追溯 UN | 验证方式 | | --- | --- | --- | --- | -| SR-001 | | UN-001 | | +| SR-001 | 待确认 | UN-001 | 待确认 | + +## 术语和缩写 + +(列出正文用到的术语与缩写;无则写 NA。) ## 追溯 @@ -45,6 +130,12 @@ | 审核 | | | | | 批准 | | | | +## 历史记录 + +| 版本 | 日期 | 修订人 | 更改内容 | +| --- | --- | --- | --- | +| A | {{generated_at}} | | 新建 | + ## 说明 -本文档由研发小队在任务快照上生成,属于设计历史记录。后续补充的材料不会改变本次内容。 +本文档由研发小队在任务快照上生成,属于设计历史记录。系统需求须追溯到需求输入中的 UR/UN 或材料。不编造未提出的功能。不做疗效宣称。冲突需求并列,不自行取舍。后续补充的材料不会改变本次内容。 diff --git a/templates/docs/rd_user_needs.md b/templates/docs/rd_user_needs.md index b15514c9..afed456a 100644 --- a/templates/docs/rd_user_needs.md +++ b/templates/docs/rd_user_needs.md @@ -10,18 +10,46 @@ ## 结论 -(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) +(一句话:用户需求是否完整、可验证且可向下追溯。信息不足标「待确认」。不适用则写「本文件不适用」及理由。) ## 适用性 - 适用 / 不适用:{{applicability}} - 不适用理由:{{na_rationale}} +## 用户与使用场景 + +(写满四段式。目标用户、使用环境、操作流程与痛点。不做疗效宣称。) + +| 项 | 内容 | +| --- | --- | +| 目标用户 | 待确认 | +| 使用环境 | 待确认 | +| 关键操作流程 | 待确认 | + ## 用户需求 +(写满:每条原子需求;空行用「待确认」示例填满至少一行。) + | ID | 需求陈述 | 来源 | 优先级 | 验证方式 | | --- | --- | --- | --- | --- | -| UN-001 | | | | | +| UN-001 | 待确认 | 待确认 | 待确认 | 待确认 | + +## 约束与非功能期望 + +(写满四段式。法规/标准约束、可用性、可靠性、服务与培训期望。) + +| ID | 类型 | 陈述 | 优先级 | +| --- | --- | --- | --- | +| UN-N-001 | 待确认 | 待确认 | 待确认 | + +## 冲突与待澄清 + +(写满四段式。相互冲突的用户诉求并列,不自行取舍。) + +| 冲突/澄清项 | 选项 | 建议下一步 | +| --- | --- | --- | +| 待确认 | 待确认 | 待确认 | ## 追溯