From 3bcf9647a125838b7da028f03a4dff9fd2d78918 Mon Sep 17 00:00:00 2001 From: bruce Date: Wed, 10 Jun 2026 23:56:20 +0800 Subject: [PATCH] =?UTF-8?q?docs(regulatory-info-package):=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E6=9D=90=E6=96=99=E5=8C=85=E7=94=9F=E6=88=90=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E5=86=B3=E7=AD=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/1.需求分析/5.第1章监管信息材料包生成.md | 14 +++-- docs/2.功能设计/5.第1章监管信息材料包生成.md | 31 +++++++--- .../3.数据库设计/5.第1章监管信息材料包生成.md | 15 ++++- docs/4.详细设计/5.第1章监管信息材料包生成.md | 56 +++++++++++++++---- docs/5.开发计划/5.第1章监管信息材料包生成.md | 45 +++++++++------ 5 files changed, 116 insertions(+), 45 deletions(-) diff --git a/docs/1.需求分析/5.第1章监管信息材料包生成.md b/docs/1.需求分析/5.第1章监管信息材料包生成.md index 091caff..0759e35 100644 --- a/docs/1.需求分析/5.第1章监管信息材料包生成.md +++ b/docs/1.需求分析/5.第1章监管信息材料包生成.md @@ -40,10 +40,11 @@ | 6 | 尽量多填 | 对说明书中可识别的产品名称、包装规格、预期用途、组成成分、储存条件、适用仪器、样本类型、检测靶标等字段尽量填入 | | 7 | 缺失项标记 | 系统新填入的缺失项使用 `/`,并设置黄色底色提醒负责人补充 | | 8 | LLM-only 标记 | 代码抽取未取到但 LLM 抽取到的字段,也需要在输出文件中高亮提示人工复核 | -| 9 | doc 能力增强 | `.doc` 文档需要具备与 `.docx` 等价的原始处理能力,不能只依赖预转换作为唯一方案 | -| 10 | zip 主输出 | 生成 `第1章 监管信息(预生成版).zip` 作为主下载入口,单文件作为辅助下载 | -| 11 | 对话唤起提示 | 在对话框底部增加本工作流的唤起提示词 | -| 12 | LLM 意图判断 | 触发判断不能只依赖固定关键词,需要引入 LLM 判断用户是否要生成第1章监管信息材料包 | +| 9 | 模板字段化 | 优先将样例模板整理为 Agent/代码可识别字段模板,使用内容控件 Tag 或稳定占位符,代码只填内容不手改格式 | +| 10 | doc 能力增强 | `.doc` 文档按能力驱动处理:有原生能力时优先原生写入,无原生能力时明确记录并允许 `.docx` 兜底,不静默输出未改写文件 | +| 11 | zip 主输出 | 生成 `第1章 监管信息(预生成版).zip` 作为主下载入口,单文件作为辅助下载 | +| 12 | 对话唤起提示 | 在对话框底部增加本工作流的唤起提示词 | +| 13 | LLM 意图判断 | 触发判断不能只依赖固定关键词,需要引入 LLM 判断用户是否要生成第1章监管信息材料包 | ### 2.2 非本期范围 @@ -444,5 +445,6 @@ | D9 | 需求分析文档新增为 `docs/1.需求分析/5.第1章监管信息材料包生成.md` | | D10 | zip 作为主入口,单文件作为辅助下载 | | D11 | 对话框底部增加工作流唤起提示词 | -| D12 | `.doc` 要实现与 `.docx` 等价能力,不能只依赖转换作为需求唯一方案 | -| D13 | 触发判断需要引入 LLM,不只依赖固定关键词 | +| D12 | 模板优先字段化,使用内容控件 Tag 或稳定占位符服务 Agent/代码填充,行标签定位仅作为兜底 | +| D13 | `.doc` 要按能力驱动实现与 `.docx` 等价能力;原生能力不可用时允许 `.docx` 兜底并明确提示 | +| D14 | 触发判断需要引入 LLM,不只依赖固定关键词 | diff --git a/docs/2.功能设计/5.第1章监管信息材料包生成.md b/docs/2.功能设计/5.第1章监管信息材料包生成.md index 348812b..11d158d 100644 --- a/docs/2.功能设计/5.第1章监管信息材料包生成.md +++ b/docs/2.功能设计/5.第1章监管信息材料包生成.md @@ -27,9 +27,10 @@ | 独立工作流 | 新增 `regulatory_info_package` 批次、节点和卡片 | | 单说明书输入 | 直接从当前对话 active 附件中选择唯一说明书;兼容最近成功文件汇总批次 | | 模板驱动 | 通过 YAML 配置维护 7 个模板、字段映射和生成策略 | +| 模板字段化 | 优先使用 Word 内容控件 Tag 或稳定占位符,让代码只写字段值,最大限度保留原格式 | | 规则 + LLM 并行抽取 | 代码抽取与 LLM 抽取并行,合并后写入模板 | | 待确认高亮 | 系统新填入的 `/`、LLM-only 字段、冲突字段均高亮 | -| `.doc` 等价处理 | 设计 `LegacyWordDocumentService`,提供与 `.docx` 一致的文档操作接口 | +| `.doc` 等价处理 | 设计 `LegacyWordDocumentService`,按能力驱动提供与 `.docx` 一致的文档操作接口;原生能力不可用时明确兜底 | | zip 主输出 | 扩展 `ExportedSummaryFile.ExportType.ZIP`,统一下载权限 | | LLM 意图路由 | 扩展路由 action,支持固定话术和 LLM 语义判断 | @@ -159,7 +160,7 @@ flowchart TD | 工作流状态 | `WorkflowNodeRun`、`WorkflowEvent` | 使用 `workflow_type=regulatory_info_package` | | 模板配置 | YAML | 便于维护 7 个模板和字段映射 | | `.docx` 操作 | `python-docx` | 表格、段落、run、底色和字体可控 | -| `.doc` 操作 | 适配器抽象 | Python 标准库不支持 `.doc` 二进制 Word 写入;设计为 COM/UNO/第三方库适配器 | +| `.doc` 操作 | 适配器抽象 | Python 标准库不支持 `.doc` 二进制 Word 写入;设计为 COM/UNO/第三方库适配器,能力不可用时使用可追溯的 `.docx` 兜底 | | zip 打包 | Python `zipfile` 标准库 | 标准库可满足打包需求 | | Excel 追溯 | `openpyxl` | 复用现有依赖 | | LLM | `review_agent.llm.generate_completion` | 统一模型调用 | @@ -281,10 +282,19 @@ templates: source_file: CH1.9 产品申报前沟通的说明.doc file_format: doc strategy: pre_submission - require_legacy_doc_native: true + prefer_legacy_doc_native: true + allow_docx_fallback: true include_in_zip: true ``` +字段映射优先级: + +| 目标类型 | 说明 | +| --- | --- | +| content_control_tag | 正式模板优先,代码按 Word 内容控件 Tag 写入 | +| placeholder | 过渡方案,替换稳定占位符并保留原 run/段落格式 | +| table_row_label | 未字段化模板的兜底方案,必须保留原单元格格式 | + ### 7.1 配置项说明 | 配置项 | 说明 | @@ -300,7 +310,8 @@ templates: | strategy | 生成策略 | | include_in_zip | 是否进入 zip | | fields | 字段映射与替换目标 | -| require_legacy_doc_native | `.doc` 是否要求原生处理能力 | +| prefer_legacy_doc_native | `.doc` 是否优先尝试原生处理能力 | +| allow_docx_fallback | 原生 `.doc` 能力不可用或失败时是否允许 `.docx` 兜底 | --- @@ -836,7 +847,8 @@ pytest tests/test_application_form_fill_*.py tests/test_file_summary_views.py te | 风险 | 说明 | 建议 | | --- | --- | --- | -| `.doc` 原生写入难度 | Python 标准库不支持 Word `.doc` 完整写入 | 优先调研 Word COM 或 LibreOffice UNO;设计适配器隔离风险 | +| `.doc` 原生写入难度 | Python 标准库不支持 Word `.doc` 完整写入 | 优先调研 Word COM 或 LibreOffice UNO;无原生能力时允许可追溯 `.docx` 兜底 | +| 模板字段化工作量 | 需要先把样例模板整理为代码可识别字段 | 优先覆盖 CH1.4、CH1.5 和声明类关键字段;缺少 Tag 时通过模板审计提前暴露 | | 样例模板文本碎片 | Word run 拆分可能导致简单字符串替换失败 | 文档写入服务需支持跨 run 替换 | | 产品列表结构复杂 | 说明书表格可能存在合并单元格和多规格 | 先覆盖目标说明书结构,再扩展通用表格归一化 | | 标准清单准确性 | 说明书未必包含标准号,知识库候选不能直接作为结论 | 候选全部高亮并进入追溯清单 | @@ -854,7 +866,8 @@ pytest tests/test_application_form_fill_*.py tests/test_file_summary_views.py te | D4 | 输入选择以 active 附件为主,兼容最近成功文件汇总批次 | | D5 | `ExportedSummaryFile.ExportType` 扩展 `zip` | | D6 | 采用 YAML 配置驱动 7 个模板 | -| D7 | `.doc` 通过 `LegacyWordDocumentService` 适配器实现与 `.docx` 等价接口 | -| D8 | 标准候选复用系统已有知识库/RAG,不新增独立 RAG | -| D9 | 前端只扩展现有对话页、工作流卡片、快捷提示和状态轮询 | -| D10 | 本轮先产出功能设计;数据库设计先在本文档中给出,后续可拆成正式数据库设计文档 | +| D7 | 模板字段优先使用内容控件 Tag 或稳定占位符,行标签定位仅作为兜底 | +| D8 | `.doc` 通过 `LegacyWordDocumentService` 适配器实现与 `.docx` 等价接口,原生能力不可用时允许可追溯兜底 | +| D9 | 标准候选复用系统已有知识库/RAG,不新增独立 RAG | +| D10 | 前端只扩展现有对话页、工作流卡片、快捷提示和状态轮询 | +| D11 | 本轮先产出功能设计;数据库设计先在本文档中给出,后续可拆成正式数据库设计文档 | diff --git a/docs/3.数据库设计/5.第1章监管信息材料包生成.md b/docs/3.数据库设计/5.第1章监管信息材料包生成.md index 4e0aba9..476329b 100644 --- a/docs/3.数据库设计/5.第1章监管信息材料包生成.md +++ b/docs/3.数据库设计/5.第1章监管信息材料包生成.md @@ -50,6 +50,8 @@ erDiagram 说明:`ra_workflow_node_run`、`ra_workflow_event`、`ra_exported_summary_file` 通过 `workflow_type` 与 `workflow_batch_id` 支持多工作流。本功能统一使用 `workflow_type=regulatory_info_package`。 +现状补充:当前通用节点表已有 `batch + node_code` 唯一约束主要服务文件汇总批次。RIP 批次不应强依赖 `FileSummaryBatch.batch`,因此实现时必须为 `workflow_type + workflow_batch_id + node_code` 增加数据库唯一约束,或在创建节点时使用同等幂等逻辑,避免同一 RIP 批次重复初始化节点。 + --- ## 三、表结构设计 @@ -211,6 +213,13 @@ erDiagram | node_group | regulatory_info_package | | batch_id | 可为空;如为兼容旧查询,不建议绑定文件汇总批次 | +幂等约束建议: + +| 约束/策略 | 字段 | 说明 | +| --- | --- | --- | +| uq_ra_node_workflow_batch_code | workflow_type, workflow_batch_id, node_code | 推荐新增数据库唯一约束,防止同一 RIP 批次重复节点 | +| get_or_create 幂等 | workflow_type, workflow_batch_id, node_code | 若暂不改通用表约束,节点初始化必须使用该组合做代码层幂等 | + 建议新增节点: ```text @@ -543,6 +552,7 @@ CREATE INDEX idx_ra_rip_batch_created | JSONField 默认值 | 使用 `default=list` 或 `default=dict`,禁止使用可变对象字面量 | | 外键删除策略 | conversation/user 使用 CASCADE;输入附件和文件汇总批次建议 PROTECT 或 SET_NULL,避免历史批次断链 | | `source_summary_item_id` | 当前没有强制外键到 `FileSummaryItem`,可先保存 ID,后续需要强约束时再改 FK | +| 工作流节点幂等 | RIP 节点不得只依赖 `WorkflowNodeRun.batch + node_code` 唯一约束;必须使用 `workflow_type + workflow_batch_id + node_code` 保证幂等 | | `.doc` 失败记录 | `.doc` 原生适配器不可用或执行失败时必须写入 `risk_notes` 和 artifact metadata;若 `.docx` 兜底成功则 generated_files 状态为 `fallback_success` | | zip 主入口 | zip 导出记录的 `export_category` 固定为 `regulatory_info_package` | | 单文件下载 | 7 个生成文件也写入 `ExportedSummaryFile`,作为辅助下载 | @@ -562,8 +572,9 @@ CREATE INDEX idx_ra_rip_batch_created | 6 | zip 导出 | `ExportedSummaryFile` 支持 `export_type=zip` | | 7 | 下载权限 | 非批次所属用户不能下载 RIP 导出 | | 8 | 节点事件 | `WorkflowNodeRun` 和 `WorkflowEvent` 可通过 `workflow_type=regulatory_info_package` 查询 | -| 9 | 通知记录 | 通知成功、失败和重试次数可落库 | -| 10 | JSON 摘要 | 缺失项、LLM-only、冲突项、风险提示结构符合本文约定 | +| 9 | 节点幂等 | 同一 `workflow_type + workflow_batch_id + node_code` 不会重复创建节点 | +| 10 | 通知记录 | 通知成功、失败和重试次数可落库 | +| 11 | JSON 摘要 | 缺失项、LLM-only、冲突项、风险提示结构符合本文约定 | --- diff --git a/docs/4.详细设计/5.第1章监管信息材料包生成.md b/docs/4.详细设计/5.第1章监管信息材料包生成.md index 2d4c3a8..a7998dd 100644 --- a/docs/4.详细设计/5.第1章监管信息材料包生成.md +++ b/docs/4.详细设计/5.第1章监管信息材料包生成.md @@ -27,11 +27,13 @@ | 独立工作流 | 使用 `workflow_type=regulatory_info_package`,拥有独立批次、产物、通知和卡片 | | 独立模块 | 新增 `review_agent/regulatory_info_package/`,与 `application_form_fill` 平级 | | 模型集中 | Django 模型仍集中放在 `review_agent/models.py` | +| 节点幂等 | `WorkflowNodeRun` 必须按 `workflow_type + workflow_batch_id + node_code` 幂等创建或加唯一约束 | | 输入优先级 | 用户消息指定文件名优先;其次 active 附件;再兼容最近成功文件汇总 | | 模板固定 | 固定处理第1章监管信息 7 个模板 | +| 模板字段化 | 生成逻辑优先写 Word 内容控件 Tag 或稳定占位符,不以手工调整表格格式为前提 | | 规则优先可演示 | 规则抽取可独立跑通;LLM 失败最多重试 3 次,失败后继续 | | 文档并发生成 | 工作流整体串行,`generate_docs` 节点内部每个文档可独立线程并发处理 | -| `.doc` 兜底 | 优先原生 `.doc` 写入;失败后允许生成 `.docx` 兜底文件 | +| `.doc` 兜底 | 能力驱动:有 Word COM/UNO 时优先原生 `.doc`;无原生能力或原生失败时允许生成 `.docx` 兜底文件 | | zip 只含成功文件 | zip 只打包成功或兜底成功的文件;失败文件不进入 zip | | 高亮规则 | 缺失和 LLM-only 黄底;冲突黄底红字 | | 追溯输出 | 用户下载 Excel;JSON 仅保存到后台 logs 目录 | @@ -91,7 +93,7 @@ review_agent/ | views.py | health、start、status、select-input 接口 | | input_select.py | 根据用户消息、active 附件、文件汇总选择说明书 | | template_config.py | YAML 加载、校验、hash | -| template_repository.py | 定位样例模板、复制到批次目录 | +| template_repository.py | 定位样例模板、复制到批次目录、审计字段 Tag/占位符 | | instruction_extract.py | 说明书段落、章节、表格和组成成分表解析 | | field_extract.py | 规则抽取与 LLM 抽取并行执行,LLM 最多 3 次重试 | | field_merge.py | 合并字段,输出缺失、LLM-only、冲突和高亮决策 | @@ -248,7 +250,8 @@ class TemplateSpec: file_format: str strategy: str include_in_zip: bool - require_legacy_doc_native: bool = False + prefer_legacy_doc_native: bool = False + allow_docx_fallback: bool = True fields: list[dict[str, Any]] = field(default_factory=list) ``` @@ -414,7 +417,31 @@ review_agent/regulatory_info_package/templates/regulatory_info_package_templates | code 唯一 | 防止覆盖产物 | | source_file 存在 | 缺失则配置错误 | | strategy 合法 | 必须命中生成策略 | -| doc 模板标记 | `.doc` 模板需声明 `require_legacy_doc_native` | +| doc 模板标记 | `.doc` 模板需声明 `prefer_legacy_doc_native`,并配置允许 `.docx` 兜底 | + +### 8.1 模板字段化约定 + +为避免生成时破坏 Word 表格、复选框、字号、缩进和合并单元格,本工作流优先使用字段化模板: + +| 方式 | 使用场景 | 说明 | +| --- | --- | --- | +| Word 内容控件 Tag | 正式模板优先 | 在 Word 中为产品名、申请人、复选框、日期、说明文字等填写区设置稳定 Tag,代码按 Tag 写入 | +| 稳定占位符 | 过渡方案 | 使用 `{{ product_name }}` 等不会影响版式的占位符,代码替换占位符所在 run | +| 行标签定位 | 兜底方案 | 仅用于未字段化的旧模板,必须保留原单元格、段落和 run 格式 | + +模板配置中的字段目标优先级: + +```yaml +targets: + - type: content_control_tag + tag: product_name + - type: placeholder + marker: "{{ product_name }}" + - type: table_row_label + label: 产品名称 +``` + +模板加载时必须执行字段审计:关键字段缺少 Tag/占位符时给出清晰错误或降级说明;不得静默使用会破坏格式的整格重建策略。 --- @@ -504,7 +531,9 @@ class DocumentAdapter(Protocol): | 方法 | 说明 | | --- | --- | | replace_text | 支持段落与表格中的文本替换,需处理 run 拆分 | -| fill_table_cell | 按行标签定位目标单元格 | +| fill_content_control | 按内容控件 Tag 填写文本、日期或复选框 | +| replace_placeholder | 按稳定占位符替换文本,保留占位符所在 run/段落格式 | +| fill_table_cell | 按行标签定位目标单元格,仅作为未字段化模板的兜底 | | replace_table | 重建 CH1.5 产品列表表格 | | apply_highlight | 使用 `w:shd` 设置黄色底色 | | apply_conflict_style | 黄色底色 + 红字 | @@ -528,10 +557,11 @@ class LegacyDocDocumentAdapter: 执行顺序: -1. 优先尝试 `WordComDocAdapter` 原生打开 `.doc` 并保存 `.doc`。 -2. 原生失败时,尝试将 `.doc` 另存为 `.docx`,再交给 `DocxDocumentAdapter`。 -3. 兜底成功时,输出 `CH1.9 产品申报前沟通的说明.docx`。 -4. 原生和兜底均失败时,该文件状态为 `failed`,不进入 zip。 +1. 执行能力探测:Word COM、LibreOffice UNO 或其他可写 `.doc` 能力。 +2. 有原生能力时优先尝试原生打开 `.doc` 并保存 `.doc`。 +3. 无原生能力或原生失败时,尝试生成同语义 `.docx` 兜底文件,再交给 `DocxDocumentAdapter`。 +4. 兜底成功时,输出 `CH1.9 产品申报前沟通的说明.docx`,状态为 `fallback_success`。 +5. 原生和兜底均失败时,该文件状态为 `failed`,不进入 zip。 兜底成功 `adapter_summary.doc`: @@ -693,6 +723,7 @@ class RegulatoryInfoPackageWorkflowExecutor: | --- | --- | | prepare | 确认说明书,或 waiting_user | | template_copy | 复制 7 个模板 | +| template_audit | 审计模板字段 Tag/占位符,记录缺失和降级策略 | | text_extract | 抽取说明书章节和表格 | | field_extract | 规则 + LLM 并行抽取 | | field_merge | 合并字段、高亮决策 | @@ -917,8 +948,8 @@ def notify_completion(batch: RegulatoryInfoPackageBatch, exports: list[ExportedS | --- | --- | | D1 | 详细设计文档路径为 `docs/4.详细设计/5.第1章监管信息材料包生成.md` | | D2 | 模型集中在 `review_agent/models.py`,业务模块为 `review_agent/regulatory_info_package/` | -| D3 | `.doc` 采用 A+C:优先 Word COM 原生处理,同时设计适配器层和能力探测 | -| D4 | `.doc` 原生失败时允许 `.docx` 兜底;兜底文件名为 `CH1.9 产品申报前沟通的说明.docx` | +| D3 | `.doc` 采用能力驱动策略:探测 Word COM/UNO 等原生能力,有能力时优先原生处理 | +| D4 | `.doc` 无原生能力或原生失败时允许 `.docx` 兜底;兜底文件名为 `CH1.9 产品申报前沟通的说明.docx` | | D5 | zip 只包含成功或兜底成功文件,失败文件不进入 zip | | D6 | LLM 最多重试 3 次,失败后使用规则结果继续 | | D7 | 缺失和 LLM-only 黄底,冲突黄底红字 | @@ -928,4 +959,5 @@ def notify_completion(batch: RegulatoryInfoPackageBatch, exports: list[ExportedS | D11 | 追溯 Excel 可下载,JSON 只放后台 logs | | D12 | 本期不新增字段级数据库表 | | D13 | 工作流串行,文档生成节点内部可多线程 | -| D14 | 本轮只产出详细设计,不写代码、不生成迁移 | +| D14 | 模板优先字段化,正式填充路径使用内容控件 Tag 或稳定占位符,行标签定位仅作为兜底 | +| D15 | 本轮只产出详细设计,不写代码、不生成迁移 | diff --git a/docs/5.开发计划/5.第1章监管信息材料包生成.md b/docs/5.开发计划/5.第1章监管信息材料包生成.md index 812aa03..88e071d 100644 --- a/docs/5.开发计划/5.第1章监管信息材料包生成.md +++ b/docs/5.开发计划/5.第1章监管信息材料包生成.md @@ -19,7 +19,9 @@ ## 一、开发计划目标 -本开发计划面向 Codex 执行,目标是把 `regulatory_info_package` 独立工作流按可验证、可回滚、可阶段提交的方式落地。计划以现有自动填表工作流 `application_form_fill` 为主要参考,但保持独立模块、独立批次、独立产物、独立通知和独立前端卡片。 +本开发计划面向 Codex 执行,目标是把 `regulatory_info_package` 独立工作流按可验证、可回滚、可阶段验收的方式落地。计划以现有自动填表工作流 `application_form_fill` 为主要参考,但保持独立模块、独立批次、独立产物、独立通知和独立前端卡片。 + +现状裁决:当前最新代码中尚未存在 `regulatory_info_package` 正式工作流,本计划按“新建正式材料包工作流”执行;不得把该功能并入或改造 `application_form_fill`。 开发完成后,用户可在对话中上传或指定产品说明书,并通过“根据说明书生成第1章监管信息”触发工作流。系统基于 `docs/0.原始材料/第1章 监管信息` 样例模板生成 7 个监管信息文件,以 `第1章 监管信息(预生成版).zip` 作为首位下载入口,同时提供单文件和追溯 Excel 辅助下载。 @@ -32,18 +34,20 @@ | 工作流独立 | 新增 `workflow_type=regulatory_info_package`,不并入 `application_form_fill` | | 模块独立 | 新增 `review_agent/regulatory_info_package/`,服务与自动填表平级 | | 模型集中 | Django 模型继续放在 `review_agent/models.py` | +| 节点幂等 | RIP 节点必须基于 `workflow_type + workflow_batch_id + node_code` 做幂等创建或数据库唯一约束 | | 单说明书输入 | 用户消息指定文件名优先,其次 active 附件,再兼容最近成功文件汇总 | | 多候选处理 | 不做选择弹窗,通过对话反问用户确认说明书文件名 | | 模板固定 | 固定处理第1章监管信息 7 个模板 | +| 模板字段化 | 优先把模板整理为 Agent/代码可识别的字段模板,使用内容控件 Tag 或稳定占位符;代码只填字段,不依赖手工改格式 | | 抽取策略 | 规则抽取和 LLM 抽取并行,LLM 最多重试 3 次,失败后规则结果继续 | | 文档生成 | 工作流节点串行,`generate_docs` 节点内部每个文档独立线程处理 | -| `.doc` 策略 | CH1.9 优先原生 `.doc` 写入,失败后允许 `.docx` 兜底 | +| `.doc` 策略 | CH1.9 能力驱动:探测到 Word COM/UNO 时优先原生 `.doc`,无原生能力时明确记录并允许 `.docx` 兜底 | | zip 策略 | zip 只包含成功或兜底成功文件,失败文件不进入 zip | | 高亮策略 | 缺失项 `/` 黄底;LLM-only 黄底;冲突黄底红字 | | 追溯策略 | 用户下载 Excel;JSON 只写后台 logs 目录 | | 前端策略 | 只做最小接入,不单独建设新页面或独立样式体系 | | TDD | 新行为先写失败测试,再实现 | -| Git 提交 | 每阶段验证通过后生成提交摘要并本地提交 | +| Git 提交 | 每阶段验证通过后生成提交摘要;是否本地提交由用户确认 | | 用户变更保护 | 不回滚、不覆盖用户已有未提交变更 | --- @@ -156,7 +160,7 @@ pytest tests/test_file_summary_views.py -k download | 目标 | 生成数据库迁移并覆盖基础模型行为 | | 修改范围 | `review_agent/migrations/`、`tests/` | | 验收标准 | migration 可应用;模型测试覆盖批次号、状态、artifact、通知、zip export type | -| Codex 执行提示 | 请生成迁移并新增 `tests/test_regulatory_info_package_models.py`,优先覆盖模型字段默认值和导出类型。 | +| Codex 执行提示 | 请生成迁移并新增 `tests/test_regulatory_info_package_models.py`,优先覆盖模型字段默认值、导出类型,以及 `WorkflowNodeRun` 在 RIP 批次下的幂等/唯一节点创建。 | ### RIP-1 阶段验证 @@ -182,10 +186,10 @@ pytest tests/test_regulatory_info_package_models.py tests/test_file_summary_view | 项 | 内容 | | --- | --- | -| 目标 | 配置 7 个样例模板、输出文件名、策略和 `.doc` 标记 | +| 目标 | 配置 7 个样例模板、输出文件名、策略、字段 Tag/占位符映射和 `.doc` 标记 | | 修改范围 | `review_agent/regulatory_info_package/templates/regulatory_info_package_templates_v1.yaml` | -| 验收标准 | 7 个模板完整;zip 名称为 `第1章 监管信息(预生成版).zip` | -| Codex 执行提示 | 请按详细设计录入模板配置,source_dir 指向样例目录,CH1.9 必须声明 `require_legacy_doc_native: true`。 | +| 验收标准 | 7 个模板完整;zip 名称为 `第1章 监管信息(预生成版).zip`;字段映射优先使用内容控件 Tag 或稳定占位符 | +| Codex 执行提示 | 请按详细设计录入模板配置,source_dir 指向样例目录,字段 targets 优先写 content_control_tag 或 placeholder;CH1.9 声明 `prefer_legacy_doc_native: true` 且允许 docx fallback。 | ### RIP-2-003 实现配置加载、模板仓库和存储目录 @@ -193,8 +197,17 @@ pytest tests/test_regulatory_info_package_models.py tests/test_file_summary_view | --- | --- | | 目标 | 实现 YAML 加载校验、模板复制、批次目录创建、路径安全检查 | | 修改范围 | `template_config.py`、`template_repository.py`、`storage.py` | -| 验收标准 | 配置错误可返回清晰错误;模板只复制到批次目录;不写原始材料目录 | -| Codex 执行提示 | 请实现配置加载和模板复制服务,所有路径必须校验位于批次工作目录内,原始模板目录只读。 | +| 验收标准 | 配置错误可返回清晰错误;模板只复制到批次目录;不写原始材料目录;能审计模板是否包含所需 Tag/占位符 | +| Codex 执行提示 | 请实现配置加载、模板复制和模板字段审计服务,所有路径必须校验位于批次工作目录内,原始模板目录只读。 | + +### RIP-2-004 模板字段化整理与审计 + +| 项 | 内容 | +| --- | --- | +| 目标 | 将样例模板升级为代码友好的字段模板,不手工改生成文件格式 | +| 修改范围 | `docs/0.原始材料/第1章 监管信息` 的模板副本或 `review_agent/regulatory_info_package/templates/field_manifest.yaml` | +| 验收标准 | CH1.4 关键字段、复选框、声明类产品名/申请人位置有稳定 Tag 或占位符;审计缺失字段时测试失败 | +| Codex 执行提示 | 请优先使用 Word 内容控件 Tag;若暂不具备内容控件编辑能力,则使用不会影响版式的稳定占位符,并在配置中记录字段与目标位置。 | ### RIP-2 阶段验证 @@ -380,8 +393,8 @@ pytest tests/test_regulatory_info_package_docx_writer.py tests/test_regulatory_i | --- | --- | | 目标 | 探测 Word COM、LibreOffice UNO 或可用兜底能力 | | 修改范围 | `services/legacy_doc_document.py` | -| 验收标准 | 当前环境无原生能力时返回清晰 capability,不崩溃 | -| Codex 执行提示 | 请先实现能力探测和接口骨架,Windows Word COM 可作为优先实现;不可用时进入 docx 兜底。 | +| 验收标准 | 当前环境无原生能力时返回清晰 capability,不崩溃;测试不要求本机必须安装 Word 或 LibreOffice | +| Codex 执行提示 | 请先实现能力探测和接口骨架,Windows Word COM/LibreOffice UNO 可作为原生能力;不可用时明确进入 docx 兜底。 | ### RIP-7-002 实现 CH1.9 原生写入与 docx 兜底 @@ -389,8 +402,8 @@ pytest tests/test_regulatory_info_package_docx_writer.py tests/test_regulatory_i | --- | --- | | 目标 | CH1.9 优先 `.doc` 输出,失败时生成同语义 `.docx` | | 修改范围 | `legacy_doc_document.py`、`package_generate.py` | -| 验收标准 | 原生成功状态 success;兜底成功状态 fallback_success;两者失败不进入 zip | -| Codex 执行提示 | 请把原生失败和兜底失败都写入 `adapter_summary` 和 `risk_notes`,不要静默转换。 | +| 验收标准 | 有原生能力时原生成功状态 success;无原生能力或原生失败但兜底成功时状态 fallback_success;两者失败不进入 zip | +| Codex 执行提示 | 请把能力探测、原生失败和兜底失败都写入 `adapter_summary` 和 `risk_notes`,不要静默转换。 | ### RIP-7-003 补充 doc 适配器测试 @@ -565,9 +578,9 @@ pytest tests/test_regulatory_info_package_models.py tests/test_regulatory_info_p | 用户变更保护 | 不得回滚或覆盖用户已有未提交变更 | | 过程日志 | 每阶段记录关键命令结果和既有失败 | | 阶段验证 | 每阶段完成后运行对应验证命令 | -| 阶段提交 | 每阶段验证通过后生成提交摘要并本地提交 | +| 阶段提交 | 每阶段验证通过后生成提交摘要;是否执行 `git commit` 由用户确认 | | 回归保护 | 文件汇总、法规核查、自动填表现有测试不得回归 | -| doc 风险隔离 | `.doc` 原生处理失败不得阻断其他 6 个 docx 文件生成 | +| doc 风险隔离 | `.doc` 原生能力不可用或原生处理失败不得阻断其他 6 个 docx 文件生成 | | 外部依赖隔离 | LLM、通知、Word COM 均需可 mock,测试不依赖真实外部服务 | | 下载安全 | 所有导出下载必须通过所属用户权限校验 | @@ -588,7 +601,7 @@ pytest tests/test_regulatory_info_package_models.py tests/test_regulatory_info_p 5. 不回滚、不覆盖用户已有未提交变更。 6. LLM、通知、Word COM 等外部能力必须可 mock。 7. 每阶段完成后运行该阶段验证命令。 -8. 验证通过后生成提交摘要并本地提交。 +8. 验证通过后生成提交摘要,是否本地提交等待用户确认。 9. 最后使用 docs/0.原始材料/目标产品说明书.docx 做端到端验收。 ```