merge: feature/rdev-template-depth
This commit is contained in:
@@ -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`)。
|
||||
@@ -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 四工作流门禁挂钩
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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` |
|
||||
|
||||
@@ -248,6 +248,7 @@ imports:
|
||||
- app/uow
|
||||
sysadmin:
|
||||
- config
|
||||
engineeringdashboard: []
|
||||
|
||||
table_owners:
|
||||
document_records:
|
||||
|
||||
@@ -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。
|
||||
@@ -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 重复提交。
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"doc_id": "doc_proj6424_intake"
|
||||
}
|
||||
@@ -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)与本阶段材料一致,无冲突
|
||||
@@ -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. 专员已标注的出处是否保留;无依据的分析是否被误删。
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
+23
@@ -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
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
+40
@@ -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"
|
||||
}
|
||||
+391
@@ -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 | 行业标准 |
|
||||
|
||||
---
|
||||
|
||||
**说明**:本文档由研发小队在任务快照上生成,属于设计历史记录。后续补充的材料不会改变本次内容,须通过变更控制流程更新。
|
||||
@@ -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、签字、附件正文;附件清单类只建索引。
|
||||
- 声明不适用时须写完整理由(首期若任务在规划期关闭则不生成正文)。
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -0,0 +1 @@
|
||||
{"code":"INTERNAL","message":"请求无法完成","request_id":"req_cdebce820010fd8b","error":"INTERNAL"}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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` 章节骨架(如 ## 结论、## 适用性、专业正文各节、## 追溯、## 待确认清单、## 签署 等)的基础上,将专员的草稿进行逻辑润色、出处溯源和终审定稿输出。
|
||||
|
||||
**待确认清单**:在模板对应章节中集中列出文中所有「待确认」。
|
||||
@@ -34,6 +34,8 @@
|
||||
|
||||
## DHF 设计控制纪律(研发设计控制流程 rd_* 任务)
|
||||
|
||||
> **分工红线**:模板管结构与占位;overlay/运行时管写作纪律与粒度下限。详见 [08-rdev模板写作规范](../../.doc/system-design/project-workflow/08-rdev模板写作规范.md)。
|
||||
|
||||
适用于 ISO 13485 设计历史文件(DHF)类受控文档:
|
||||
|
||||
- 模板各章节必须写满;禁止残留括号提示或空表壳。
|
||||
|
||||
@@ -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] + "..."
|
||||
}
|
||||
@@ -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{"严禁代签", "严禁伪造附件内容"},
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,16 +10,42 @@
|
||||
|
||||
## 结论
|
||||
|
||||
(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
(一句话:同类产品主要不良事件模式及对本项目设计输入的含义。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
|
||||
## 适用性
|
||||
|
||||
- 适用 / 不适用:{{applicability}}
|
||||
- 不适用理由:{{na_rationale}}
|
||||
|
||||
## 同类产品不良事件信息正文
|
||||
## 检索范围与方法
|
||||
|
||||
(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。)
|
||||
(写满四段式。数据库/时间窗/关键词/产品对照范围;未检索到须说明已尝试路径。禁止编造 URL 与事件编号。)
|
||||
|
||||
| 项 | 内容 |
|
||||
| --- | --- |
|
||||
| 数据源 | 待确认 |
|
||||
| 时间窗 | 待确认 |
|
||||
| 关键词/产品范围 | 待确认 |
|
||||
|
||||
## 不良事件摘要表
|
||||
|
||||
(写满四段式。按模式归类;无公开信息写「未检索到公开信息」。)
|
||||
|
||||
| 事件模式 | 典型表现 | 频次/量级(若可知) | 出处 |
|
||||
| --- | --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 对本项目的设计含义
|
||||
|
||||
(写满四段式。每条事件模式对应设计输入/风险控制/标签或培训含义。)
|
||||
|
||||
| 事件模式 | 设计输入含义 | 风险控制线索 | 是否已纳入 DI/风险 |
|
||||
| --- | --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 信息局限与后续监视
|
||||
|
||||
(写满四段式。数据局限、需窗口核实项、上市后监视建议。)
|
||||
|
||||
## 追溯
|
||||
|
||||
|
||||
@@ -10,16 +10,48 @@
|
||||
|
||||
## 结论
|
||||
|
||||
(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
(一句话:设计输入条目是否齐套、缺口是否已识别。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
|
||||
## 适用性
|
||||
|
||||
- 适用 / 不适用:{{applicability}}
|
||||
- 不适用理由:{{na_rationale}}
|
||||
|
||||
## 设计输入清单正文
|
||||
## 输入来源与分类
|
||||
|
||||
(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。)
|
||||
(写满四段式。说明输入来自用户需求、法规标准、风险、既往产品经验等;分类口径写清。)
|
||||
|
||||
| 分类 | 说明 | 主要来源文档 |
|
||||
| --- | --- | --- |
|
||||
| 功能/性能 | 待确认 | 待确认 |
|
||||
| 法规/标准 | 待确认 | 待确认 |
|
||||
| 安全/风险 | 待确认 | 待确认 |
|
||||
|
||||
## 设计输入条目表
|
||||
|
||||
(写满四段式。每条原子化;状态用「已收录/待确认/不适用」。禁止空表。)
|
||||
|
||||
| 输入 ID | 陈述摘要 | 分类 | 来源 | 状态 | 关联规格书条款 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| DI-001 | 待确认 | 待确认 | 待确认 | 待确认 | RD-DI-SPEC |
|
||||
|
||||
## 缺口与冲突
|
||||
|
||||
(写满四段式。列出缺失输入、相互冲突输入及处理建议;无冲突写「当前未识别冲突」。)
|
||||
|
||||
| 缺口/冲突 | 影响阶段 | 建议动作 | 责任方 |
|
||||
| --- | --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 齐套性检查
|
||||
|
||||
(写满四段式。对照设计输入规格书、用户需求、法规清单做齐套结论。)
|
||||
|
||||
| 检查项 | 结果 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 与 RD-DI-SPEC 对齐 | 待确认 | 待确认 |
|
||||
| 与 RD-UN / RD-SR 对齐 | 待确认 | 待确认 |
|
||||
| 法规输入已覆盖 | 待确认 | 待确认 |
|
||||
|
||||
## 追溯
|
||||
|
||||
|
||||
@@ -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 | 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 追溯
|
||||
|
||||
|
||||
@@ -10,18 +10,42 @@
|
||||
|
||||
## 结论
|
||||
|
||||
(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
(一句话:DHF 文件计划与阶段节奏是否足以支撑设计控制。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
|
||||
## 适用性
|
||||
|
||||
- 适用 / 不适用:{{applicability}}
|
||||
- 不适用理由:{{na_rationale}}
|
||||
|
||||
## 设计控制策略与阶段划分
|
||||
|
||||
(写满四段式。策划→输入→输出→验证→确认→转化的阶段目标与门禁。禁止省略套话。)
|
||||
|
||||
| 阶段 | 目标 | 门禁/评审 | 主要输出 |
|
||||
| --- | --- | --- | --- |
|
||||
| 01 策划 | 待确认 | 待确认 | 待确认 |
|
||||
| 03 设计输入 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## DHF 文件计划清单
|
||||
|
||||
| 阶段 | 文件 | 记录归属 | 计划完成 |
|
||||
| --- | --- | --- | --- |
|
||||
| 策划 | 项目建议书、设计开发计划任务书 | DHF | |
|
||||
(写满:每行给出计划完成时点与责任角色;未知写「待确认」。)
|
||||
|
||||
| 阶段 | 文件 | 记录归属 | 计划完成 | 责任角色 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 策划 | 项目建议书、设计开发计划任务书 | DHF | 待确认 | 待确认 |
|
||||
| 设计输入 | 设计输入清单/规格书、UN/SR、风险相关 | DHF | 待确认 | 待确认 |
|
||||
|
||||
## 资源、接口与依赖
|
||||
|
||||
(写满四段式。内外部接口、关键依赖、外包边界。)
|
||||
|
||||
| 依赖/接口 | 提供方 | 对本计划影响 |
|
||||
| --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 进度与变更控制入口
|
||||
|
||||
(写满四段式。基线计划、变更如何回流到本任务书与 DHF 清单。)
|
||||
|
||||
## 追溯
|
||||
|
||||
|
||||
@@ -10,18 +10,46 @@
|
||||
|
||||
## 结论
|
||||
|
||||
(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
(一句话:主要危害是否已识别、控制与验证线索是否齐全。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
|
||||
## 适用性
|
||||
|
||||
- 适用 / 不适用:{{applicability}}
|
||||
- 不适用理由:{{na_rationale}}
|
||||
|
||||
## 分析范围与方法
|
||||
|
||||
(写满四段式。分析对象、生命周期阶段、所用方法(如初步危害分析)、参考标准。禁止编造。)
|
||||
|
||||
| 项 | 内容 |
|
||||
| --- | --- |
|
||||
| 分析对象 | 待确认 |
|
||||
| 方法 | 待确认 |
|
||||
| 参考 | 待确认 |
|
||||
|
||||
## 危害-原因-控制-验证
|
||||
|
||||
(写满:至少一行「待确认」示例;剩余风险不得空白无说明。)
|
||||
|
||||
| 危害 | 原因 | 控制措施 | 验证 | 剩余风险 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| | | | | 待确认 |
|
||||
| 待确认 | 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 风险评价摘要
|
||||
|
||||
(写满四段式。按可接受准则汇总不可接受项与需进一步控制项。)
|
||||
|
||||
| 危害 ID | 初始风险 | 控制后风险 | 可接受? | 备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 与设计输入的接口
|
||||
|
||||
(写满四段式。哪些危害驱动了设计输入/软件需求/标签警告。)
|
||||
|
||||
| 危害 | 对应设计输入/需求 | 标签/培训线索 |
|
||||
| --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 追溯
|
||||
|
||||
|
||||
@@ -10,16 +10,43 @@
|
||||
|
||||
## 结论
|
||||
|
||||
(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
(一句话:是否建议立项、产品定位与目标市场是否清晰、主要风险是否可接受。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
|
||||
## 适用性
|
||||
|
||||
- 适用 / 不适用:{{applicability}}
|
||||
- 不适用理由:{{na_rationale}}
|
||||
|
||||
## 项目建议书正文
|
||||
## 项目背景与立项依据
|
||||
|
||||
(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。)
|
||||
(写满:结论句 → 要点列表 → 解读 → 出处。覆盖客户/市场痛点、法规与商业驱动、与公司能力匹配。缺项「待确认」。不做疗效宣称。)
|
||||
|
||||
## 产品定义与范围
|
||||
|
||||
(写满四段式。覆盖产品名称/类型、预期用途、目标用户与使用场景、明确不在范围内的项。)
|
||||
|
||||
| 项 | 内容 |
|
||||
| --- | --- |
|
||||
| 产品类型 | 待确认 |
|
||||
| 预期用途 | {{intended_use}} |
|
||||
| 目标市场 | {{target_market}} |
|
||||
| 范围外 | 待确认 |
|
||||
|
||||
## 目标、里程碑与资源假设
|
||||
|
||||
(写满四段式。覆盖阶段目标、关键里程碑、人力/外包/关键设备假设;预算与商务报价不在本文展开。)
|
||||
|
||||
| 里程碑 | 计划时点 | 交付物 | 依赖 |
|
||||
| --- | --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 主要风险与对策概览
|
||||
|
||||
(写满四段式。技术/法规/供应链/进度风险各至少一条;无则说明「材料未提供」并列入待确认。)
|
||||
|
||||
| 风险 | 影响 | 对策/缓解 | 残余 |
|
||||
| --- | --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 追溯
|
||||
|
||||
|
||||
@@ -10,16 +10,46 @@
|
||||
|
||||
## 结论
|
||||
|
||||
(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
(一句话:适用法规/标准是否识别完毕、强制与非强制是否区分。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
|
||||
## 适用性
|
||||
|
||||
- 适用 / 不适用:{{applicability}}
|
||||
- 不适用理由:{{na_rationale}}
|
||||
|
||||
## 法规和标准清单正文
|
||||
## 监管路径与目标市场
|
||||
|
||||
(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。)
|
||||
(写满四段式。目标市场/注册路径、器械分类假设、是否含软件/无菌/有源等。字段不足标「待确认」。)
|
||||
|
||||
| 项 | 内容 |
|
||||
| --- | --- |
|
||||
| 目标市场 | {{target_market}} |
|
||||
| 器械分类假设 | 待确认 |
|
||||
| 监管路径 | 待确认 |
|
||||
|
||||
## 适用法规清单
|
||||
|
||||
(写满四段式。每条写清效力、对本项目含义;禁止编造标准号。)
|
||||
|
||||
| 法规 | 效力范围 | 对本项目含义 | 证据/出处 |
|
||||
| --- | --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 适用标准与指导原则
|
||||
|
||||
(写满四段式。强制标准与指导原则分列;指导原则标注「非强制」。)
|
||||
|
||||
| 标准/指导原则 | 强制/非强制 | 适用条款要点 | 符合性活动 |
|
||||
| --- | --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 不适用项与理由
|
||||
|
||||
(写满四段式。明确声明不适用的法规/标准及完整理由;无则写「当前无额外不适用项」。)
|
||||
|
||||
| 法规/标准 | 不适用理由 |
|
||||
| --- | --- |
|
||||
| 待确认 | 待确认 |
|
||||
|
||||
## 追溯
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
## 结论
|
||||
|
||||
(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
(一句话:风险管理范围、准则与职责是否明确。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
|
||||
## 适用性
|
||||
|
||||
@@ -19,7 +19,41 @@
|
||||
|
||||
## 风险管理范围与职责
|
||||
|
||||
(范围、职责、准则、评审节点。缺项写「待确认」。)
|
||||
(写满四段式。产品范围、生命周期覆盖、角色与职责矩阵。)
|
||||
|
||||
| 角色 | 职责 | 权限边界 |
|
||||
| --- | --- | --- |
|
||||
| 风险管理负责人 | 待确认 | 待确认 |
|
||||
| 设计代表 | 待确认 | 待确认 |
|
||||
| 法规/质量代表 | 待确认 | 待确认 |
|
||||
|
||||
## 风险可接受准则
|
||||
|
||||
(写满四段式。严重度/概率等级定义、可接受区域、需受益-风险分析的条件。禁止空壳。)
|
||||
|
||||
| 等级 | 严重度定义 | 概率定义 | 可接受性 |
|
||||
| --- | --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 活动与交付物
|
||||
|
||||
(写满四段式。危害分析、风险控制、剩余风险评价、风险报告及与设计评审的衔接。)
|
||||
|
||||
| 活动 | 输入 | 输出 | 责任方 |
|
||||
| --- | --- | --- | --- |
|
||||
| 危害分析 | 待确认 | RD-HAZARD 等 | 待确认 |
|
||||
| 风险控制验证 | 待确认 | 待确认 | 待确认 |
|
||||
| 风险报告 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 评审节点表
|
||||
|
||||
(写满四段式。策划/输入/输出/验证/确认各节点的风险管理评审要求。)
|
||||
|
||||
| 节点 | 评审内容 | 通过准则 | 计划时点 |
|
||||
| --- | --- | --- | --- |
|
||||
| 设计输入 | 待确认 | 待确认 | 待确认 |
|
||||
| 设计输出 | 待确认 | 待确认 | 待确认 |
|
||||
| 验证/确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 追溯
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
## 结论
|
||||
|
||||
(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
(一句话:配置项识别与维护策略是否足以支撑发布与变更。无软件可声明不适用。信息不足标「待确认」。)
|
||||
|
||||
本阶段可声明不适用:无软件成分时可声明不适用。
|
||||
|
||||
@@ -19,9 +19,39 @@
|
||||
- 适用 / 不适用:{{applicability}}
|
||||
- 不适用理由:{{na_rationale}}
|
||||
|
||||
## 软件配置及维护计划正文
|
||||
## 配置项识别
|
||||
|
||||
(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。)
|
||||
(写满四段式。源代码、构建脚本、工具链、文档、第三方组件等。)
|
||||
|
||||
| CI 标识 | 描述 | 责任人角色 | 基线节点 |
|
||||
| --- | --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 版本、基线与发布控制
|
||||
|
||||
(写满四段式。版本号规则、基线建立时机、发布审批入口。)
|
||||
|
||||
| 活动 | 规则/时机 | 审批 |
|
||||
| --- | --- | --- |
|
||||
| 版本号 | 待确认 | 待确认 |
|
||||
| 基线 | 待确认 | 待确认 |
|
||||
| 发布 | 待确认 | 待确认 |
|
||||
|
||||
## 变更与维护流程
|
||||
|
||||
(写满四段式。变更请求、影响分析、回归范围、紧急修复。)
|
||||
|
||||
| 变更类型 | 流程要点 | 回归要求 |
|
||||
| --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 第三方与工具维护
|
||||
|
||||
(写满四段式。开源/外购组件清单入口、漏洞响应、工具升级策略。)
|
||||
|
||||
| 组件/工具 | 来源 | 维护策略 |
|
||||
| --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 追溯
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
## 结论
|
||||
|
||||
(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
(一句话:软件生命周期模型与计划是否适用。无软件成分可声明不适用并写理由。信息不足标「待确认」。)
|
||||
|
||||
本阶段可声明不适用:无软件成分时可声明不适用。
|
||||
|
||||
@@ -19,9 +19,43 @@
|
||||
- 适用 / 不适用:{{applicability}}
|
||||
- 不适用理由:{{na_rationale}}
|
||||
|
||||
## 软件开发计划正文
|
||||
## 开发模型与软件安全分级
|
||||
|
||||
(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。)
|
||||
(写满四段式。选用的开发生命周期模型、软件安全分类/分级假设及依据。禁止编造标准条款号。)
|
||||
|
||||
| 项 | 内容 |
|
||||
| --- | --- |
|
||||
| 开发模型 | 待确认 |
|
||||
| 软件安全分级假设 | 待确认 |
|
||||
| 依据 | 待确认 |
|
||||
|
||||
## 生命周期阶段与活动
|
||||
|
||||
(写满四段式。各阶段活动、输入输出、退出准则。)
|
||||
|
||||
| 阶段 | 主要活动 | 输出 | 退出准则 |
|
||||
| --- | --- | --- | --- |
|
||||
| 需求 | 待确认 | 待确认 | 待确认 |
|
||||
| 设计 | 待确认 | 待确认 | 待确认 |
|
||||
| 实现 | 待确认 | 待确认 | 待确认 |
|
||||
| 验证 | 待确认 | 待确认 | 待确认 |
|
||||
| 发布/维护 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 工具、环境与配置管理
|
||||
|
||||
(写满四段式。IDE/编译器/CI、配置项范围、基线策略;详见配置及维护计划的交叉引用。)
|
||||
|
||||
| 工具/配置项 | 用途 | 版本/基线策略 |
|
||||
| --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 验证准则与问题管理
|
||||
|
||||
(写满四段式。单元/集成/系统测试准入准出、缺陷分级与关闭准则、变更控制入口。)
|
||||
|
||||
| 活动 | 准入 | 准出 | 问题关闭准则 |
|
||||
| --- | --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 追溯
|
||||
|
||||
|
||||
@@ -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 | | |
|
||||
|
||||
## 已有材料摘要
|
||||
|
||||
|
||||
@@ -10,16 +10,40 @@
|
||||
|
||||
## 结论
|
||||
|
||||
(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
(一句话:总体架构是否满足设计输入、关键子系统与接口是否明确。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
|
||||
## 适用性
|
||||
|
||||
- 适用 / 不适用:{{applicability}}
|
||||
- 不适用理由:{{na_rationale}}
|
||||
|
||||
## 系统设计方案正文
|
||||
## 系统概述与上下文
|
||||
|
||||
(按本阶段专业结构写。缺项写「待确认」。不做疗效宣称。)
|
||||
(写满四段式。产品定位、使用场景、系统边界、与外部环境/用户的关系。可用 Mermaid 上下文图并加标题。不做疗效宣称。)
|
||||
|
||||
## 子系统划分与职责
|
||||
|
||||
(写满四段式。列出子系统/模块、职责、关键接口归属。)
|
||||
|
||||
| 子系统 | 职责 | 关键接口 | 备注 |
|
||||
| --- | --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 关键架构决策
|
||||
|
||||
(写满四段式。技术路线、软硬件划分、安全架构要点、备选方案否决理由。)
|
||||
|
||||
| 决策点 | 选用方案 | 否决方案 | 依据 |
|
||||
| --- | --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 接口与数据流
|
||||
|
||||
(写满四段式。人机/电气/数据/网络接口;主数据流与控制流。未知标「待确认」。)
|
||||
|
||||
| 接口 ID | 双方 | 类型 | 协议/约束 | 来源需求 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| IF-001 | 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 追溯
|
||||
|
||||
|
||||
@@ -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 或材料。不编造未提出的功能。不做疗效宣称。冲突需求并列,不自行取舍。后续补充的材料不会改变本次内容。
|
||||
|
||||
@@ -10,18 +10,46 @@
|
||||
|
||||
## 结论
|
||||
|
||||
(一句话。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
(一句话:用户需求是否完整、可验证且可向下追溯。信息不足标「待确认」。不适用则写「本文件不适用」及理由。)
|
||||
|
||||
## 适用性
|
||||
|
||||
- 适用 / 不适用:{{applicability}}
|
||||
- 不适用理由:{{na_rationale}}
|
||||
|
||||
## 用户与使用场景
|
||||
|
||||
(写满四段式。目标用户、使用环境、操作流程与痛点。不做疗效宣称。)
|
||||
|
||||
| 项 | 内容 |
|
||||
| --- | --- |
|
||||
| 目标用户 | 待确认 |
|
||||
| 使用环境 | 待确认 |
|
||||
| 关键操作流程 | 待确认 |
|
||||
|
||||
## 用户需求
|
||||
|
||||
(写满:每条原子需求;空行用「待确认」示例填满至少一行。)
|
||||
|
||||
| ID | 需求陈述 | 来源 | 优先级 | 验证方式 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| UN-001 | | | | |
|
||||
| UN-001 | 待确认 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 约束与非功能期望
|
||||
|
||||
(写满四段式。法规/标准约束、可用性、可靠性、服务与培训期望。)
|
||||
|
||||
| ID | 类型 | 陈述 | 优先级 |
|
||||
| --- | --- | --- | --- |
|
||||
| UN-N-001 | 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 冲突与待澄清
|
||||
|
||||
(写满四段式。相互冲突的用户诉求并列,不自行取舍。)
|
||||
|
||||
| 冲突/澄清项 | 选项 | 建议下一步 |
|
||||
| --- | --- | --- |
|
||||
| 待确认 | 待确认 | 待确认 |
|
||||
|
||||
## 追溯
|
||||
|
||||
|
||||
Reference in New Issue
Block a user