# 2026-10-17 导出与采集时间浏览器验收 本轮基于已合入的检索导出、导出工作台和资料生命周期页面,在隔离 PostgreSQL/pgvector 与默认生命周期 FastAPI、Vite、真实浏览器之间联调。全部账号、资料和查询均为合成测试;没有加载 Embedding、调用生成模型或产生领域实验结论。 ## 基线与准备 - 旧 AGit [PR #33](https://gitea.kronecker.cc/saint/border-red-post-nalati/pulls/33) 关闭未合并,其普通分支通过真正 merged 的 [PR #34](https://gitea.kronecker.cc/saint/border-red-post-nalati/pulls/34) 合入 dev,保留原实现并增加下载响应的显式 `Cache-Control: no-store`。原 head、替代 head 和 merge 均已核对为最新 dev 祖先。 - [PR #36](https://gitea.kronecker.cc/saint/border-red-post-nalati/pulls/36) 的导出页面和 [PR #38](https://gitea.kronecker.cc/saint/border-red-post-nalati/pulls/38) 的来源生命周期页面也已合入。从最新 dev 创建本阶段分支,没有叠加待审功能或合入 main。 - 独立 HTTP 初始化合成来源、带微秒采集时间的关联文档、已审核知识和文本发布,并实际执行 22 条条目/chunk 关键词检索,准备其中一条的兼容请求上下文。这些是测试准备,不能称为浏览器录入或向量推理。 ## 浏览器已实际验证的路径 | 路径 | 结果 | |---|---| | 匿名访问导出页 | 跳转登录并保留回跳路径;管理员登录后回到导出页 | | 历史分页 | 显示 22 条,第一页 20 条、第二页 2 条;两端翻页按钮正确禁用 | | 跨页选择 | 第一页选择一条 chunk 记录,第二页选择一条条目记录,仍保留两条选择 | | 可选上下文 | 勾选关联 RAG 准备上下文后触发真实浏览器文件下载 | | 下载文件核对 | 文件实际落盘;manifest 为 2 条检索和 1 条上下文;记录区 SHA-256 与页面显示一致,每个 payload 与原保存快照一致 | | 文档时区缺陷复现 | 原采集时间为 `2026-10-16T12:34:56.789123+08:00`,仅修改备注却变成 `2026-10-16T04:34:00+08:00` | | 修正后时间回填 | 编辑页显示当地时钟的 `12:34:56.789`,而非 UTC 时钟的 `04:34`;新建表单采集时间留空,要求明确填写 | | 修正后仅修改备注 | 页面保存成功;独立 API 读取确认原带微秒的时间字符串完全保留,文档版本递增 | | 文档历史 | 页面展开最新版本快照,可看到版本 4 及原 `12:34:56.789123+08:00` 采集时间 | 浏览器实际下载: ![跨页选择并下载](assets/export-acceptance/export-download.jpg) 备注修改后的历史快照: ![采集时间保留原微秒值](assets/export-acceptance/document-collected-at.jpg) ## 修正内容 原表单把 `toISOString()` 的 UTC 时钟直接填入 `datetime-local`,提交时又按本地时区解析,造成时区偏移;截取到分钟还会丢失秒和更高精度。 新增日期转换函数:回填使用本地时钟,支持秒/毫秒输入;若管理员没有修改时间,直接保留服务端原时间字符串,避免丢失微秒或在夏令时重叠时刻改变实际瞬间。明确修改时间时才转换为带时区的 ISO 时间。新建文档不再预填当前时间作为采集事实,仍由必填校验要求输入。 最新 dev 新合入的知识编辑页使用了相同的 UTC 截取方式,本轮同步复用此转换函数,保留其无采集时间时的空值语义;该知识页面的修改通过共享函数回归和构建验证,没有冒充新的浏览器操作。 为复核修正效果,缺陷复现后只在隔离合成数据上通过独立 HTTP 恢复原采集时间,再重新加载页面执行仅改备注的浏览器验证。该恢复属于测试基线准备,没有冒充浏览器操作;不自动修复或猜测既有业务资料的真实采集时间。 ## 独立 HTTP 交叉核对 以下和浏览器操作分开记录: - 文档修改后关联知识回到 pending,旧文本发布的检索返回 409;没有继续使用旧审核依据。 - 被活动知识/文档引用的文档、来源删除返回 409;过期版本修改返回 409。 - 单独可丢弃来源/文档经过修改和软删除后,正文详情隐藏,删除历史快照保留。 - 来源与文档修订后再次通过 HTTP 导出原选择,记录区原始字节与首次浏览器下载完全一致;manifest 的导出时间/编号允许变化,生成用量/费用仍未采集。 - 下载响应 `Cache-Control: no-store`;普通用户直接请求导出返回 403。 ## 验证命令和边界 - `npm run test:datetime`:**6 passed**,覆盖中国时区、UTC、负偏移跨日、夏令时重叠、显式修改、微秒与空值;这些是 Node 时区单元测试,不等同于多浏览器验收。 - `npm run test:session`:**3 passed**;`npm run build`(含类型检查):通过。 - `pytest -q backend/tests/test_exports.py backend/tests/test_catalog.py`:**49 passed**;`ruff check backend`、`ruff format --check backend`:通过。本轮未把此前全量 254 项结果当作本阶段重新执行的结果。 - 原生删除确认框使本次浏览器控制无法继续完成确认;该浏览器删除路径未验收。相关删除保护、软删除与历史保留仅由上述独立 HTTP 和后端专项覆盖,仍需人工复核确认交互。没有据此放宽删除保护或修改确认机制。 - Docker、生产 HTTPS、多浏览器、浏览器改密、领域资料/问题集及生成模型实际调用仍不在本轮已完成范围。 复现时使用单独数据库或隔离 Schema、合成账号和明确的采集时间,按上述步骤比较下载原始字节及修改前后时间;环境、密码、原始 JSONL、数据库、日志和本机路径不入库。验证结束后关闭测试服务并删除本轮隔离 Schema。截图只保留合成数据,导出下载文件和原始检查记录保存在 Git 元数据目录。