- 招标文件解析后可以追加补遗 / 澄清:单独解析、扣 1 次;新条目标「补遗 N」进正式清单,清单回到草稿(AD1)
- 同一种日期、时间不同的旧条目标「已被补遗 N 更新」,逐条确认更新或保留两条(AD2、AD3)
- 项目字段的新值在概览「采用 / 不采用」:采用时以补遗为准、清掉人工值;采用截止时间时日期条目一起确认;
没确认前查标用旧值,检查预览提示(AD4)
- 补遗不改项目名称、编号、采购人、代理机构、法律体系(更正公告标题会被抽成项目名称);时间比较按北京时间补时区
- 接口:fields/{key}/pending、checklist-items/{id}/supersession;清单项 origin_document、superseded_by;
关键日期 replaces;解析结果 dates_superseded、fields_pending;检查预览 pending_updates
- 前端:补遗模式的上传页、解析页结果、概览确认、读标页来源筛选和日期确认、检查预览提示
- 决策 AD1–AD6;方案和落地记录 docs/architecture/addendum-plan.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
12 KiB
补遗追加实现方案 v0.1(2026-11-05)
范围:FR-M2-10 补遗追加(简化版):追加的补遗 / 澄清文件单独解析、扣 1 次解析,新条目标注来源并入清单;日期类字段以最新文件为准,在旧值上标「已被补遗 N 更新」,由用户确认;不自动判断条目「新增 / 变更 / 作废」(P1)。 依据:
03-functional-requirements.md、02-user-journeys.mdJ2 第 1 步、01-scope-roles.md(「追加解析 + 来源标注」,影响分析是 P1)、data-model.md§5.2「补遗」、openapi.yaml(/projects/{id}/fields/{key}/pending、/checklist-items/{id}/supersession)、原型project-new.html?addendum=1parsing.html?addendum=1checklist.htmlproject.html的关键日期卡。 状态:AD1–AD6 已全部按建议确认(2026-11-05,docs/decisions.md)。
0. 结论速览
- 一半已经有了:后端上传时可以选补遗 / 澄清(编号「补遗 N」「澄清 N」),能单独解析、扣 1 次解析、失败退回;新条目记着来自哪份文件;项目字段的新值和旧值不同时先放进待确认(
pending_value),不覆盖。 - 缺的:日期类条目的「已被补遗 N 更新」关联;两个确认接口(字段新值、日期条目);并入后清单回到草稿;前端的追加入口、解析结果、确认界面、来源筛选。
- 按 FR 只做日期类的自动关联。原型里「★ 参数原为 480G、补遗改成 960G」那种逐条对照属于「变更判断」,是 P1,这次不做(AD2)。
- 补遗的新条目直接进正式清单,和招标文件的新旧条目都查:宁可多报,不漏报(AD1)。
- 没有补遗样本:10 份样本里一份都没有。这次用虚构的更正公告测链路;国动项目如果有更正公告,请一起给我,这是第一份真实补遗。
1. 现状
| 环节 | 现在 | 要补的 |
|---|---|---|
| 上传、编号 | role = addendum / clarification,各自从 1 编号 |
前端入口 |
| 解析、扣点 | 和招标文件同一条流水线,扣 1 次解析,失败、超时、取消退回 | 解析结果页按补遗写(新增几条、哪些日期有新值) |
| 清单项来源 | origin_document_id 指向补遗;但接口的 origin_label 只有「AI」「人工添加」 |
origin_label 对补遗来的条目写「补遗 1」;读标页按来源筛选;并入后清单回到草稿 |
| 项目字段 | 新值和旧值不同 → pending_value,等确认 |
确认接口和界面;确认后同步冗余列 |
| 日期类条目 | 没有关联(superseded_by_id 列已建,没写) |
并入时关联、确认接口、界面 |
| 分包 | 补遗不改已有的分包 | 不变 |
2. 并入时做什么(后端)
补遗解析完、并入清单时,在现有的 checklist.merge 之后多做三件事:
- 新条目照常进清单:和招标文件一样按校验结果进正式清单或待确认区,标「补遗 N」。
- 关联日期类条目:补遗里每条有具体时间的「日期与递交」条目(投标截止、开标、提疑截止、保证金截止、投标有效期),在更早的文件(招标文件、编号更小的补遗)里找同一种日期、还在正式清单里的条目,时间不同的把旧条目的
superseded_by_id指向新条目,等用户确认。时间相同的不关联(补遗只是复述)。 - 清单回到草稿:已确认的清单改为草稿,历史版本保留,要求重新确认(原型:「补遗 1 并入后待重新确认」)。
解析任务的结果里加:items_added(新增几条)、dates_superseded(几处日期有新值)、fields_pending(几个项目字段有新值),解析页按这三个数写。
3. 确认(后端)
按契约实现两个接口:
POST /projects/{id}/fields/{key}/pending(accept: true / false):- 采用:补遗的值变成 AI 值(出处换成补遗那一句),清掉人工值(以补遗为准;用户之后还可以再改),冗余列同步;
- 不采用:丢掉待确认值,保持原值;
- 采用投标截止时间时,清单里「投标截止」日期条目的更新一起确认(AD3),不用在读标页再点一次;
- 都写审计(
project_field.resolve_pending)。
POST /checklist-items/{id}/supersession(accept: true / false,对旧条目调用):- 采用:旧条目软删除(可以恢复),新条目保留;
- 保留两条:解除关联,两条都在,由用户自己处理;
- 都写审计(
checklist_item.resolve_supersession)。
接口返回里补上已有字段:清单项的 superseded_by(新条目编号、来自哪份补遗)、清单概况的 superseded_pending(还有几处没确认)、关键日期的 superseded_pending。
没确认之前查标用旧值(AD4):项目字段的契约就是「确认后才生效」(data-model.md §5.2)。检查预览提示「补遗 1 带来的新值还有 N 处没确认」,不阻止发起检查(红线 4)。确认后截止时间变了,已有的检查结果按 PI5 提示重新检查。
4. 前端
- 追加入口:概览页右上角和读标页清单栏各放一个「追加补遗 / 澄清」,进新建项目页的补遗模式(原型
project-new.html?addendum=1)。补遗模式下不填项目名称,文件类型选补遗或澄清答复,说明写「补遗单独解析,新条目标注『补遗 N』并入清单。标博士不判断哪些旧条目已作废,并入后由你核对」,按钮旁写扣 1 次解析。招标文件还没解析完时不显示入口(AD5)。 - 解析页:标题「解析补遗 1」;完成后写「新增 N 条 · M 处日期有新值 · K 个项目字段有新值 · 清单回到草稿,核对后重新确认」,下一步「核对补遗」进读标页、只看这份补遗的条目。
- 概览页:
- 项目要点里有待确认值的字段写「补遗 1:新值 → 原值」,带出处,给「采用 / 不采用」;
- 关键日期卡:被更新、还没确认的日期显示「已被补遗 1 更新,待确认」;确认后显示新值并注「已按补遗 1 更新 · 原为 11月18日 09:30」(原型
project.html)。
- 读标页:
- 来源筛选:全部 / 招标文件 / 补遗 1 / ……,每项带条数;
- 被更新的日期条目写「已被补遗 1 更新:新值 ……」,给「确认更新(删除旧条目)」和「保留两条」;
- 并入后顶部提示「补遗 1 新增 N 条。标博士不判断哪些旧条目被它改了或作废了,请核对:改了的旧条目可以修改或删除」,带「只看补遗 1」。
- 查标页:检查预览里有没确认的新值时出上面那条提示。
5. 测试
- 虚构一份更正公告样例(
server/tests/fixtures/addendum-mini.pdf,内容全虚构):改投标截止时间、开标时间,新增一条 ★ 参数,复述一条没改的日期。 - 集成测试:追加 → 解析 → 扣 1 次 → 新条目标「补遗 1」、清单回到草稿、截止时间进待确认、日期条目关联(复述的不关联);字段采用 / 不采用;采用截止时间时日期条目一起确认;日期条目采用(旧条目软删除、可以恢复)/ 保留两条;检查预览的提示;只读项目 409。
- 假模型能不能从样例里抽出日期要看它的规则;抽不出时测试里用接口建条目。浏览器里走一遍追加到确认的全程。
- 用真实模型对这份虚构样例跑一次解析看看抽取结果,花费几分钱(AD6)。
6. 工作量和顺序
- 后端:并入时关联日期、清单回到草稿、两个确认接口、接口字段补齐、检查预览提示,以及测试样例和测试。约半天。
- 前端:补遗模式的上传页、解析页的补遗结果、概览页的确认、读标页的来源筛选和日期确认。约半天。
7. 待确认事项
| 编号 | 事项 | 建议 |
|---|---|---|
| AD1 | 补遗的新条目进正式清单还是待确认区 | 按招标文件同一套规则进正式清单(没出处、校验没过的照样进待确认区),标「补遗 N」,读标页给「只看补遗 N」和核对提示,清单回到草稿要求重新确认。新旧条目都在、都查,宁可多报,不漏报;全放待确认区的话,用户不逐条采纳就查不到补遗的新要求 |
| AD2 | 哪些条目自动标「已被补遗更新」 | 只做日期类(同一种日期、时间不同),按 FR。原型里参数类「原为 480G → 现为 960G」的逐条对照是变更判断,P1;先等真实补遗样本看写法 |
| AD3 | 怎么确认 | 字段在概览页逐个「采用 / 不采用」,日期条目在读标页逐条确认;采用投标截止时间时清单里的「投标截止」条目一起确认。采用时清掉人工值,以补遗为准 |
| AD4 | 没确认之前查标用哪个值 | 旧值,确认后生效(数据模型原定);检查预览提示还有几处没确认,不阻止检查 |
| AD5 | 招标文件没解析完能不能追加补遗 | 不能,界面上招标文件解析成功后才显示入口。没有招标文件时补遗的日期没有可关联的旧值 |
| AD6 | 用真实模型对虚构样例跑一次解析 | 跑一次(DeepSeek,几分钱),看抽取对补遗写法(「原为……现更正为……」)的表现;结果只记录,这次不按它调提示词 |
8. 落地记录(2026-11-05)
- 后端:
checklist/addendum.py(并入时关联日期条目、确认 / 保留两条、采用截止时间时一起确认「投标截止」条目);project/edit.resolve_pending(采用时补遗的值变成 AI 值、出处换成补遗那一句、清掉人工值);清单项接口补origin_document、superseded_by,origin_label对补遗来的条目写「补遗 N」;清单概况superseded_pending;关键日期replaces(「已按补遗 1 更新 · 原为……」);解析结果dates_superseded、fields_pending;检查预览pending_updates。 - 补遗不改项目是谁:解析补遗时项目名称、编号、采购人、代理机构、法律体系不进待确认。测试里发现,更正公告的标题会被抽成「项目名称」,和招标文件的不同,每份补遗都会冒出一条没意义的待确认。
- 时间比较按北京时间补时区:模型给的时间有时带时区、有时不带,补遗复述原时间时不能误判成「有新值」。
- ORM 给 JSONB 列写
None存的是 JSON null,不是 SQL NULL,SQL 里数待确认值时要排除 JSON null。 - 前端:补遗模式的上传页(选补遗 / 澄清答复)、解析页的补遗结果和「核对补遗」、概览页「追加补遗 / 澄清」和字段「采用 / 不采用」、关键日期的待确认和「已按补遗 1 更新」、读标页的来源筛选、核对提示、「只看日期更新」和逐条确认、条目上的「补遗 1」标签、检查预览的提示。
- AD6 结果:用 DeepSeek Flash 对虚构的更正公告(推后递交截止时间、新增一条 ★ 参数)跑了一次解析(6 次调用):两处改动都抽对了,★ 参数归为技术参数 + 无效条款、新截止时间 12 月 8 日,出处都是「补遗 1 · 第 1 页」,没有多抽。只是一份很规整的虚构样例,「原为……现更正为……」那种写法这份样例里没有,真实补遗到了再看。
- 浏览器里走过:追加补遗 → 解析结果 → 概览采用新截止时间(项目头、要点、关键日期一起变,旧的「投标截止」条目自动删除)→ 读标页只看补遗 1。