2026-09-10 用户确认 F01–F12、原型通过,并要求按四阶段建议推进。原型验收:#1 评论 7498。阶段 3;覆盖 F01 基础、F02、F04 基础、F05 原文。
学习者粘贴英语文本,新建书籍或向本人书籍追加章节,查看处理状态并进入可读正文。
前置:#2, #3。状态:已验收关闭(2026-09-11;未验证项见结单评论)。前置尚未通过时不得标进行中;每单完成停在待验收,由用户验收后关闭。技术验证可与不依赖其结论的工作分工,但不提前冻结未验证契约。
参考常规 router/apis/service/dto/models 与迁移;SysJob 仅提供状态操作参考,cron 不能替代持久任务的幂等和恢复。
使用已验收导入/状态/阅读原型;后端补任务状态机、幂等与回退设计。
后端不为建表/API 单独画页面原型;先写数据、接口、状态、隔离与幂等契约。学习端采用 #1 已验收 v1,未做的 LinguaCafe 对照不标完成。
预计 5~8 人日(8 小时/人日),包含本单设计、前后端实现、相关测试、修正和文档;是规划估算,不是交付日期或 AI 运行时间。仅 F 范围,X 系列不纳入。数据变更先在隔离测试库验证迁移/回退,保留既有数据和原型。
实施时按影响更新 Architecture-and-Code-Map、Business-Rules-and-Glossary、Local-Development-and-Verification;需求变化更新 Product-Requirements-Overview,交付单补实际部署恢复文档。Wiki 先写再回读同步;结束评论记录测试、未验证内容、提交及 revision。工单正文保留基线,重要变化追加评论。
Gitea MCP 指向其他站点,沿用目标 git.ilapage.cn API 回退;凭据仅进入进程。
2026-09-10 用户在当前会话指示“执行 Gitea 工单 #5”,并明确:使用独立任务分支、保留已有改动、不自行合并已有 PR、停在待验收、不实施 #21;同时指出 #3 的 Python NLP 目前仍只是独立验证,正式接入前必须确认“Go+Python NLP”还是“全 Go”,不能默认该问题已解决;#4 的真机详细测试证据缺口保留。
前置核对:#2、#18、#3、#4 均已通过用户验收并关闭,本单声明的依赖 #2、#3 满足。PR #17/#19/#20/#22 仍未合并;本单分支 feat/5-paste-chapter-reading 基于已验收的 feat/4-reading-selection-spike,不合并任何已有 PR。
feat/5-paste-chapter-reading
feat/4-reading-selection-spike
本次用户确认的两项边界:
实现计划:schema v3 新增 books/chapters/ingest_jobs 三张表;粘贴文本用于新建书籍或向本人书籍追加章节;持久任务状态机(pending/processing/ready/failed)含启动恢复与幂等(客户端 requestId,重复提交不重复生成章节,失败任务重试复用同一章节);全部接口按认证身份过滤所有权,他人编号返回 404,后台任务只使用任务行内的 owner,不接受客户端用户 ID;学习端补齐粘贴导入、书库/章节状态、失败重试与原文阅读;MySQL 集成测试覆盖“书库→导入→处理中/失败/重试→就绪→阅读”、Unicode 原文保留与越权拒绝。
风险与回退:仅新增表和接口,不改动既有账号、空间、会话与审计数据;回退=停止 API,将 lexgo_schema 版本从 3 改回 2 并恢复上一二进制,新增表保留不删除。不实施 #21。真机手机证据仍按 #4 记录保持缺失,不用桌面窄屏代替。
Gitea MCP 指向其他站点,本单继续使用目标站点 git.ilapage.cn API 回退;凭据仅进入进程。
git.ilapage.cn
提交:a55708cd37c7eb4f706d1cf573a54d44692f67ca(分支 feat/5-paste-chapter-reading,已推送) PR:#23,基准分支 feat/4-reading-selection-spike,与既有 PR 链一致;未合并任何已有 PR。
a55708cd37c7eb4f706d1cf573a54d44692f67ca
按用户确认(评论 7644)实现:Go-only 处理,不接入 Python NLP;一次粘贴=一个章节,单次上限 100000 Unicode code point,语言当前只接受 en,原文按收到的字符串逐字保留。“Go+Python NLP 还是全 Go”仍未决,本单不视为已解决,正式接入前须用户再次确认。
lexgo_books
lexgo_chapters
lexgo_ingest_jobs
owner_id
UNIQUE(book_id,ordinal)
UNIQUE(owner_id,request_key)
server/app/lexgo/library.go
ingest.go
router.go
cmd/lexgo/main.go
POST /books
POST /books/:id/chapters
GET /books
GET /books/:id
GET /chapters/:id
GET /jobs/:id
POST /jobs/:id/retry
originalText
jobId
ownerId
ImportView
LibraryView
BookView
ReaderView
pre-wrap
stores/library.ts
python scripts/server.py test-integration
LEXGO_TEST_DB_NAME=lexgo_test_issue5
test:unit --run
build
test:e2e
harness.py check --strict
pending → ready
sha256
ce7357ea22a3
duplicate=true
textContent
white-space
处理中就绪后的书库页与阅读页(工单附件):
其余附件:书库、390×844 阅读页。截图未经 Agent 目视复核(本会话模型不能读取图片),功能断言来自上面的程序化检查。
lexgo_dev 由 v2 显式迁移到 v3:迁移前后 sys_user 4、lexgo_spaces 4、lexgo_sessions 3、lexgo_login_logs 23、lexgo_operation_logs 1 完全一致,新增三张表。本机按 supervisor 流程操作:停止 lexgo-api → build → migrate → 启动,/healthz 200,lexgo-admin 与 lexgo-learner 的 PID 未变化。
sys_user 4
lexgo_spaces 4
lexgo_sessions 3
lexgo_login_logs 23
lexgo_operation_logs 1
/healthz
回退:停止 API,把 lexgo_schema 中 id=1 的版本从 3 改回 2,并恢复上一二进制;三张新表保留不删除,旧程序不读写它们。未在开发库演练回退,v2→v3 数据保留与重复迁移仅由隔离测试库覆盖。
lexgo_schema
本单新建虚构账号 issue5_a(id=6)、issue5_b(id=8),口令只在本机忽略的 .local/issue5-accounts.json;lexgo_dev 中 issue5_a 名下保留 1 本虚构书(bookId=1,2 章就绪)供人工验收查看。未改动 admin、dev、learner_a、learner_b。
issue5_a
issue5_b
.local/issue5-accounts.json
Wiki 先写后回读,再导出核心镜像(镜像包含于上述提交):
fa7d3d66e6e68164ee97a23dc20a737fcaba7a11
ff2abb673fe97e7eaa6934f76180ffdde701da8d
b8741ac70a524bb79741183f592f19c1206cd71b
125df697d3d45dee098616d25970bb65a96727cd
5b936b75caeec89cd54f7147c842f0b66f901307
需要说明的一次失误与修复:首次写入 Wiki 时误用了 content 字段(Gitea 该接口要求 content_base64),架构页正文被写入空内容。同会话立即用本机保存的编辑前正文恢复并回读确认,#2/#4 小节与新 #5 小节均完整;Wiki 历史保留两次错误提交,上述 revision 已是修复后的版本。
content
content_base64
MCP 仍指向其他站点,本单继续使用目标站点 git.ilapage.cn 的 API。本机 git credential fill 因凭据助手要求交互而不可用,改用本机忽略的本地 Gitea 环境配置中的令牌,只读入进程,未输出、未写入仓库或工单。
git credential fill
状态保持待验收,未关闭工单;#21 未实施;未合并任何已有 PR。
用户已授权:把审核结果更新到本工单,由 DeepSeek agent 实施整改,完成后由当前主审 agent 复审。当前结论:主体已实现,但尚不满足验收要求。工单保持 open,PR #23 不合并;本评论作为最新进度,原需求基线不改写。
审核基线:分支 feat/5-paste-chapter-reading,提交 a55708cd37c7eb4f706d1cf573a54d44692f67ca;原实现基线为已验收 #4 的 ed5da31888329873cd87c50237ea111388fe35af。
ed5da31888329873cd87c50237ea111388fe35af
learner/src/stores/library.ts:341
server/app/lexgo/library.go:208
server/app/lexgo/ingest.go:145
server/cmd/lexgo/main.go:117-126
learner/src/stores/library.ts:392-405
ImportView.vue:58-68
learner/src/stores/library.ts:371-382
server/app/lexgo/library.go:472
server/app/lexgo/library.go:527
lexgo_test_issue5
执行安排:整改说明已准备;当前会话可调用模型不含 DeepSeek,尚未启动或指派替代模型,正在确认用户已有 DeepSeek agent 的接入位置。
工具回退:当前 Gitea MCP 指向 http://ilaer.eicp.net:8418,与项目 https://git.ilapage.cn 不一致,因此本次使用项目既有安全配置,通过目标仓库 Gitea API 追加并回读评论。
http://ilaer.eicp.net:8418
https://git.ilapage.cn
提交:b18f9cc(分支 feat/5-paste-chapter-reading,已推送;未改写历史,未合并任何已有 PR) PR:#23 仍指向 feat/4-reading-selection-spike,本次只追加提交。 范围:只做 R1~R4;两条“后续优化建议”已转为独立工单 #24,未混入本次提交。未接入 Python NLP,未扩展数据或权限范围。
b18f9cc
结论:确认成立。 我先用真实 API 复现:带 language 的追加请求(学习端当时的实际请求体)返回 400 请求内容无效,不带则 201。上一轮的真实联调只覆盖了 API 契约本身,没有覆盖学习端追加路径,这一点由上轮 mock 的成功响应掩盖了,属于我的验证缺口。
language
修复:学习端把新建与追加拆成两个请求类型(SubmitBookBody / SubmitChapterBody),追加只发送 requestId、title、text;后端保持严格解码与未知字段/owner 注入防护,追加沿用所属书籍的语言。
SubmitBookBody
SubmitChapterBody
测试:后端新增断言“追加带 language → 400、不带 → 201”;学习端单测断言新建带 language、追加请求体不含 language(store 与组件各一项,均先在整改前代码上失败)。真实浏览器:从书籍页进入“追加章节”→提交→回到书籍页→新章节就绪→阅读正文逐字符相等,抓取到的请求体无 language。
结论:确认成立。 claim 先独立提交,FinishIngestJob 失败后任务永久停在 processing,而 claim 只取 pending、人工重试只接受 failed,只有重启能恢复;我每批 30 秒的超时确实能触发该路径。
FinishIngestJob
修复:把启动恢复与运行期恢复合并为同一处清扫——启动阈值 0,运行期每轮清扫使用 15 秒阈值;任务领取次数达到 5 次时置为 failed(原因码 attempts_exhausted,提示“处理多次失败,请重试或重新提交”);人工重试重置尝试次数(人工操作不被自动上限阻塞);worker 每秒先清扫再处理,日志分别说明“已重新入队”与“本批未完成、等待下一次清扫”,不再出现声称已重试实际跳过的表述。任务从不创建章节,因此重复处理不会产生重复章节。
attempts_exhausted
测试:新增 TestMySQLIngestRecoveryWithoutRestart(取消上下文制造完成事务失败 → 运行期清扫恢复 → 同一章节/任务编号完成)与 TestMySQLIngestAttemptsAreBoundedAndManualRetryRestarts(预算用尽 → 停止自动领取 → failed 原因可读 → 人工重试重置后成功)。
TestMySQLIngestRecoveryWithoutRestart
TestMySQLIngestAttemptsAreBoundedAndManualRetryRestarts
真实联调:新建章节后用 SQL 把任务与章节置为 processing 且 updated_at 早于阈值(UTC),不重启服务,运行期清扫在 544 ms 内重新入队并发布为就绪;章节与任务编号不变,正文逐字符相等,全书仍为同一批章节。
updated_at
结论:确认成立。 closeBook/closeChapter 只清状态、不推进请求序号,晚到响应会写回状态并重启轮询;ImportView 提交后无条件 router.replace。
closeBook
closeChapter
router.replace
修复:两个 close 函数推进各自的请求序号并清理 loading;ImportView 记录是否已卸载,卸载后的成功响应不再触发跳转。
测试:store 两项(目录页、阅读页在响应到达前关闭 → 不写回、不重启轮询)与组件一项(提交中离开后不跳转),均在整改前代码上失败。
结论:确认成立。 retryChapter 没有应用重试返回的状态,静默刷新吞掉异常且不安排轮询,一次网络抖动就会让页面停在处理失败。
retryChapter
修复:重试被接受后先把返回的 pending 状态应用到章节列表与阅读器并重新安排轮询,再做静默刷新。
测试:store 两项(阅读页、书籍页:POST 成功 + 首次 GET 失败 + 网络恢复后自动显示就绪),整改前失败。
真实联调:用 SQL 制造真实失败任务(content_changed)后,在浏览器点击“重试”并中断紧随其后的第一次刷新,页面立即由“处理失败”变为“处理中”,随后自行变为“已就绪”,无需手工刷新。
content_changed
7 项新增前端用例在整改前的 library.ts/ImportView.vue 上运行并实际失败:追加发送 language、目录页/阅读页晚到响应写回、阅读页/书籍页重试后停在失败、组件级追加请求体、提交中离页后跳转;改回修复版本后 38 项全部通过。后端两项新用例覆盖运行期恢复与尝试上限。
library.ts
ImportView.vue
npx --yes pnpm@9.15.1 --dir learner test:unit --run
npx --yes pnpm@9.15.1 --dir learner build
npx --yes pnpm@9.15.1 --dir learner test:e2e
python -m unittest discover -s tests
POST /api/v1/books/:id/chapters
Wiki 先写后回读,再导出核心镜像(镜像含于提交 b18f9cc):
f981b86a7c6e5d2e353142d3006dcd6e0636c3ee
4bd843d1f0134f5688407b7072d98333b40b6da1
3bce5fae964b1050513c37319262679814d68f14
本地验证页同时记录了 MySQL 会话时区为 SYSTEM(本机 UTC+8)而服务按 UTC 存储 DATETIME 的差异:核对任务时间需用 UTC_TIMESTAMP,用 NOW() 会产生 8 小时假偏差(我自己第一次构造 R2 场景时就踩到,已更正后复测)。
UTC_TIMESTAMP
NOW()
状态保持待验收,未关闭工单,交回主审独立检查与复测。
审核提交:b18f9cc,相对 a55708c 的 11 个文件变更;已核对 PR #23 的当前提交与本地一致,工作区干净。
a55708c
结论:R1~R4 的修复合理,本轮未发现阻止提交用户验收的新问题。在当前单实例、同一 worker 串行清扫和处理的前提下,可以进入用户验收;这不代替用户验收,工单保持 open,PR 不合并。
本轮独立验证:专用 lexgo_test_issue5 上 Go 全包 20 项顶层用例通过;独立前端审查执行 38 项单测和 vue-tsc/Vite 构建,均通过。已核查新增回归用例,不只依据上一条交付声明。
说明与非阻塞建议:
未修改产品代码、未合并 PR、未关闭工单。长期事实无新增变化,本次只追加复审证据,不更新 Wiki。
工具回退沿用本单记录:Gitea MCP 指向不同站点,使用目标 git.ilapage.cn 的既有安全配置调用 API。
在主审报告 R1~R4 技术复审通过、可进入用户验收后,用户回复“可以结单吗”,本次按该确认结单。
验收版本:b18f9cc4a54dfb7ef4fe9f882a1b4d6a10c27997。实施与整改证据见评论 7651、7677,独立复审见评论 7686:Go 20 项顶层测试、前端 38 项单测及构建通过。
确认关闭本单;不宣称用户已另行执行完整手工测试。R3 真实浏览器竞态和 #4 真机详细证据仍未补齐,保留未验证说明;手机相关完整证据在后续体验/交付工作继续验证。正文最后一项包含手机验收,保持未勾选,避免把未验证内容标为通过。后续书库分页/截断提示与目录查询优化由 #24 跟踪。
本次仅更新工单验收状态与父单 #16 进度;不合并 PR #23 或其他 PR,不自动实施 #6/#21/#24,不改动产品代码和数据库。无新增长期技术契约,不修改 Wiki。Gitea API 回退原因沿用本单记录:MCP 指向其他站点。
No dependencies set.
The note is not visible to the blocked user.
来源与目标
2026-09-10 用户确认 F01–F12、原型通过,并要求按四阶段建议推进。原型验收:#1 评论 7498。阶段 3;覆盖 F01 基础、F02、F04 基础、F05 原文。
学习者粘贴英语文本,新建书籍或向本人书籍追加章节,查看处理状态并进入可读正文。
验收标准
依赖与执行
前置:#2, #3。状态:已验收关闭(2026-09-11;未验证项见结单评论)。前置尚未通过时不得标进行中;每单完成停在待验收,由用户验收后关闭。技术验证可与不依赖其结论的工作分工,但不提前冻结未验证契约。
参考模块与设计证据
参考常规 router/apis/service/dto/models 与迁移;SysJob 仅提供状态操作参考,cron 不能替代持久任务的幂等和恢复。
使用已验收导入/状态/阅读原型;后端补任务状态机、幂等与回退设计。
后端不为建表/API 单独画页面原型;先写数据、接口、状态、隔离与幂等契约。学习端采用 #1 已验收 v1,未做的 LinguaCafe 对照不标完成。
工作量、范围与风险
预计 5~8 人日(8 小时/人日),包含本单设计、前后端实现、相关测试、修正和文档;是规划估算,不是交付日期或 AI 运行时间。仅 F 范围,X 系列不纳入。数据变更先在隔离测试库验证迁移/回退,保留既有数据和原型。
文档与证据
实施时按影响更新 Architecture-and-Code-Map、Business-Rules-and-Glossary、Local-Development-and-Verification;需求变化更新 Product-Requirements-Overview,交付单补实际部署恢复文档。Wiki 先写再回读同步;结束评论记录测试、未验证内容、提交及 revision。工单正文保留基线,重要变化追加评论。
Gitea MCP 指向其他站点,沿用目标 git.ilapage.cn API 回退;凭据仅进入进程。
#5 启动与范围确认(用户确认边界)
2026-09-10 用户在当前会话指示“执行 Gitea 工单 #5”,并明确:使用独立任务分支、保留已有改动、不自行合并已有 PR、停在待验收、不实施 #21;同时指出 #3 的 Python NLP 目前仍只是独立验证,正式接入前必须确认“Go+Python NLP”还是“全 Go”,不能默认该问题已解决;#4 的真机详细测试证据缺口保留。
前置核对:#2、#18、#3、#4 均已通过用户验收并关闭,本单声明的依赖 #2、#3 满足。PR #17/#19/#20/#22 仍未合并;本单分支
feat/5-paste-chapter-reading基于已验收的feat/4-reading-selection-spike,不合并任何已有 PR。本次用户确认的两项边界:
实现计划:schema v3 新增 books/chapters/ingest_jobs 三张表;粘贴文本用于新建书籍或向本人书籍追加章节;持久任务状态机(pending/processing/ready/failed)含启动恢复与幂等(客户端 requestId,重复提交不重复生成章节,失败任务重试复用同一章节);全部接口按认证身份过滤所有权,他人编号返回 404,后台任务只使用任务行内的 owner,不接受客户端用户 ID;学习端补齐粘贴导入、书库/章节状态、失败重试与原文阅读;MySQL 集成测试覆盖“书库→导入→处理中/失败/重试→就绪→阅读”、Unicode 原文保留与越权拒绝。
风险与回退:仅新增表和接口,不改动既有账号、空间、会话与审计数据;回退=停止 API,将 lexgo_schema 版本从 3 改回 2 并恢复上一二进制,新增表保留不删除。不实施 #21。真机手机证据仍按 #4 记录保持缺失,不用桌面窄屏代替。
Gitea MCP 指向其他站点,本单继续使用目标站点
git.ilapage.cnAPI 回退;凭据仅进入进程。#5 实施完成,待用户验收
提交:
a55708cd37c7eb4f706d1cf573a54d44692f67ca(分支feat/5-paste-chapter-reading,已推送)PR:#23,基准分支
feat/4-reading-selection-spike,与既有 PR 链一致;未合并任何已有 PR。范围与边界
按用户确认(评论 7644)实现:Go-only 处理,不接入 Python NLP;一次粘贴=一个章节,单次上限 100000 Unicode code point,语言当前只接受 en,原文按收到的字符串逐字保留。“Go+Python NLP 还是全 Go”仍未决,本单不视为已解决,正式接入前须用户再次确认。
实现
lexgo_books、lexgo_chapters、lexgo_ingest_jobs;显式迁移,服务启动不自动迁移。owner_id在章节与任务上冗余存放,任何查询都直接按认证身份过滤;UNIQUE(book_id,ordinal)与UNIQUE(owner_id,request_key)分别阻止重复章节与重复提交。server/app/lexgo/library.go(粘贴校验、固定分章、书籍/章节/任务写入、本人归属查询、幂等、重试)、ingest.go(claim/完成/固定失败原因/启动恢复)、router.go(新路由与粘贴请求 4 MiB 体积上限)、cmd/lexgo/main.go(启动恢复 + 每秒后台处理,单实例)。POST /books、POST /books/:id/chapters、GET /books、GET /books/:id、GET /chapters/:id、GET /jobs/:id、POST /jobs/:id/retry。状态 pending/processing/ready/failed(章节与任务同词表);仅 ready 返回originalText;章节列表带jobId与可读失败原因,便于重试。owner_id,他人书籍/章节/任务编号统一 404;管理员角色不解除本人归属过滤;后台任务只使用任务行内的 owner,请求体ownerId、查询参数ownerId均返回 400。ImportView(语言固定英语、标题、正文、新建书籍/追加到已有书籍)、LibraryView(书籍与状态摘要)、BookView(章节列表、状态、失败重试)、ReaderView(原文pre-wrap逐字展示、上一章/下一章);stores/library.ts负责 1500 ms 轮询、代次与归属守卫、离开页面与退出登录后停止轮询。测试(均为实际执行)
python scripts/server.py test-integration(LEXGO_TEST_DB_NAME=lexgo_test_issue5,专用库):18 个顶层用例全部通过,其中 #5 新增 8 个(含 12 个子用例):导入→处理中→就绪→阅读完整路径、四种失败原因与可读提示、失败后重试复用同一章节、同 requestId 重复与并发提交只产生一个章节、跨账号与管理员越权的全部 404、启动恢复重入队、输入上限与边界(100000 通过、100001 拒绝、超大请求体拒绝)、Unicode 原文逐字符相等;另有 v2→v3 迁移保留既有数据的用例。test:unit --run31 项通过(session 9/library 16/reading 6);build通过(vue-tsc 类型检查 + vite 构建);test:e2e3 项通过(虚构 API 响应)。治理测试 56 项与harness.py check --strict通过。pending → ready(约 1132 ms)→ 阅读返回原文与提交内容逐字符相等(CRLF、制表符、弯引号、破折号、省略号、é+组合重音、emoji、行尾空格、空行全部保留),sha256前缀ce7357ea22a3;同 requestId 重复提交 HTTP 200duplicate=true且章节/任务编号不变,换正文 409;issue5_b 读取与越权追加、重试全部 404;追加章节 ordinal=2 且前后章节编号正确;空标题、纯空白正文、非 en、缺 requestId、超限分别 400 并可读。textContent与粘贴正文逐字符相等、white-space为pre-wrap→ “下一章”切换后正文精确相等 → 390×844 视口横向溢出 0 px。处理中就绪后的书库页与阅读页(工单附件):
其余附件:书库、390×844 阅读页。截图未经 Agent 目视复核(本会话模型不能读取图片),功能断言来自上面的程序化检查。
迁移与回退
lexgo_dev 由 v2 显式迁移到 v3:迁移前后
sys_user 4、lexgo_spaces 4、lexgo_sessions 3、lexgo_login_logs 23、lexgo_operation_logs 1完全一致,新增三张表。本机按 supervisor 流程操作:停止 lexgo-api → build → migrate → 启动,/healthz200,lexgo-admin 与 lexgo-learner 的 PID 未变化。回退:停止 API,把
lexgo_schema中 id=1 的版本从 3 改回 2,并恢复上一二进制;三张新表保留不删除,旧程序不读写它们。未在开发库演练回退,v2→v3 数据保留与重复迁移仅由隔离测试库覆盖。本机 fixture 与遗留数据
本单新建虚构账号
issue5_a(id=6)、issue5_b(id=8),口令只在本机忽略的.local/issue5-accounts.json;lexgo_dev 中 issue5_a 名下保留 1 本虚构书(bookId=1,2 章就绪)供人工验收查看。未改动 admin、dev、learner_a、learner_b。未验证与限制
文档
Wiki 先写后回读,再导出核心镜像(镜像包含于上述提交):
fa7d3d66e6e68164ee97a23dc20a737fcaba7a11ff2abb673fe97e7eaa6934f76180ffdde701da8db8741ac70a524bb79741183f592f19c1206cd71b125df697d3d45dee098616d25970bb65a96727cd5b936b75caeec89cd54f7147c842f0b66f901307需要说明的一次失误与修复:首次写入 Wiki 时误用了
content字段(Gitea 该接口要求content_base64),架构页正文被写入空内容。同会话立即用本机保存的编辑前正文恢复并回读确认,#2/#4 小节与新 #5 小节均完整;Wiki 历史保留两次错误提交,上述 revision 已是修复后的版本。Gitea 交互
MCP 仍指向其他站点,本单继续使用目标站点
git.ilapage.cn的 API。本机git credential fill因凭据助手要求交互而不可用,改用本机忽略的本地 Gitea 环境配置中的令牌,只读入进程,未输出、未写入仓库或工单。状态保持待验收,未关闭工单;#21 未实施;未合并任何已有 PR。
#5 审核整改与实施交接(2026-09-11)
用户已授权:把审核结果更新到本工单,由 DeepSeek agent 实施整改,完成后由当前主审 agent 复审。当前结论:主体已实现,但尚不满足验收要求。工单保持 open,PR #23 不合并;本评论作为最新进度,原需求基线不改写。
审核基线:分支
feat/5-paste-chapter-reading,提交a55708cd37c7eb4f706d1cf573a54d44692f67ca;原实现基线为已验收 #4 的ed5da31888329873cd87c50237ea111388fe35af。必须修复
learner/src/stores/library.ts:341对新建和追加共用包含 language 的请求;后端server/app/lexgo/library.go:208的 PasteChapterInput 不含 language,严格 JSON 解码拒绝未知字段。已用实际 Router + MySQL 测试复现前端格式被拒绝。统一请求契约,追加沿用所属书籍语言,保留未知字段/owner 注入防护。验收:从学习端向已有书籍追加成功,进入第二章,序号与前后章导航正确;补覆盖真实请求格式的回归测试,不仅 mock 成功响应。server/app/lexgo/ingest.go:145、server/cmd/lexgo/main.go:117-126。已通过领取后取消上下文复现:下一批处理后仍 processing,人工 retry 被拒绝。补单实例运行期间的异常恢复策略,不能只依赖启动恢复;防止无限快速重试和重复章节,日志不得声称已重试实际却跳过。验收:故障解除后无需重启即可完成或进入有明确原因且允许重试的 failed;原章节/任务 ID 不变;启动恢复仍有效。learner/src/stores/library.ts:392-405的 closeBook/closeChapter 只清状态;晚到响应重新填充状态并启动轮询。已内存执行实际 store 复现 closeBook 后 pending 响应令 timerCount=1。作废对应请求序号/生命周期并合理清理 loading。连同检查ImportView.vue:58-68:提交过程中离开页面后,不应被晚成功响应强制导航回来。验收:目录页、阅读页在请求完成前离开,旧响应不写回、不重启轮询、不触发意外跳转;重新进入和退出登录行为正常。learner/src/stores/library.ts:371-382没有先应用 retry 返回状态,silent GET 吞掉异常且未建立轮询。已内存执行实际 store 复现:retry resolve,但 status=failed、error为空、timerCount=0。正确应用 pending 状态并保证后续状态追踪/错误反馈。验收:书籍页与阅读页均覆盖 POST 成功 + 首次 GET 失败 + 网络恢复,自动显示最终结果,无需手工刷新。后续优化建议(记录,不作为本轮必须实施范围)
server/app/lexgo/library.go:472只返回最新 200 本,无分页/总数/截断提示;超过上限后旧书无法从书库列表访问。后续设计分页或明确限制。server/app/lexgo/library.go:527目录查询载入每章 original_text;目录应只读取所需列,降低长书开销。审核证据
lexgo_test_issue5,未操作开发库业务数据。DeepSeek 实施要求与交付
执行安排:整改说明已准备;当前会话可调用模型不含 DeepSeek,尚未启动或指派替代模型,正在确认用户已有 DeepSeek agent 的接入位置。
工具回退:当前 Gitea MCP 指向
http://ilaer.eicp.net:8418,与项目https://git.ilapage.cn不一致,因此本次使用项目既有安全配置,通过目标仓库 Gitea API 追加并回读评论。#5 审核整改完成(R1~R4),待复审
提交:
b18f9cc(分支feat/5-paste-chapter-reading,已推送;未改写历史,未合并任何已有 PR)PR:#23 仍指向
feat/4-reading-selection-spike,本次只追加提交。范围:只做 R1~R4;两条“后续优化建议”已转为独立工单 #24,未混入本次提交。未接入 Python NLP,未扩展数据或权限范围。
R1 / P1 学习端追加章节返回 HTTP 400
结论:确认成立。 我先用真实 API 复现:带
language的追加请求(学习端当时的实际请求体)返回 400 请求内容无效,不带则 201。上一轮的真实联调只覆盖了 API 契约本身,没有覆盖学习端追加路径,这一点由上轮 mock 的成功响应掩盖了,属于我的验证缺口。修复:学习端把新建与追加拆成两个请求类型(
SubmitBookBody/SubmitChapterBody),追加只发送 requestId、title、text;后端保持严格解码与未知字段/owner 注入防护,追加沿用所属书籍的语言。测试:后端新增断言“追加带 language → 400、不带 → 201”;学习端单测断言新建带 language、追加请求体不含 language(store 与组件各一项,均先在整改前代码上失败)。真实浏览器:从书籍页进入“追加章节”→提交→回到书籍页→新章节就绪→阅读正文逐字符相等,抓取到的请求体无 language。
R2 / P2 领取后完成事务失败会遗留 processing
结论:确认成立。 claim 先独立提交,
FinishIngestJob失败后任务永久停在 processing,而 claim 只取 pending、人工重试只接受 failed,只有重启能恢复;我每批 30 秒的超时确实能触发该路径。修复:把启动恢复与运行期恢复合并为同一处清扫——启动阈值 0,运行期每轮清扫使用 15 秒阈值;任务领取次数达到 5 次时置为 failed(原因码
attempts_exhausted,提示“处理多次失败,请重试或重新提交”);人工重试重置尝试次数(人工操作不被自动上限阻塞);worker 每秒先清扫再处理,日志分别说明“已重新入队”与“本批未完成、等待下一次清扫”,不再出现声称已重试实际跳过的表述。任务从不创建章节,因此重复处理不会产生重复章节。测试:新增
TestMySQLIngestRecoveryWithoutRestart(取消上下文制造完成事务失败 → 运行期清扫恢复 → 同一章节/任务编号完成)与TestMySQLIngestAttemptsAreBoundedAndManualRetryRestarts(预算用尽 → 停止自动领取 → failed 原因可读 → 人工重试重置后成功)。真实联调:新建章节后用 SQL 把任务与章节置为 processing 且
updated_at早于阈值(UTC),不重启服务,运行期清扫在 544 ms 内重新入队并发布为就绪;章节与任务编号不变,正文逐字符相等,全书仍为同一批章节。R3 / P2 离页未作废在途加载请求
结论:确认成立。
closeBook/closeChapter只清状态、不推进请求序号,晚到响应会写回状态并重启轮询;ImportView提交后无条件router.replace。修复:两个 close 函数推进各自的请求序号并清理 loading;
ImportView记录是否已卸载,卸载后的成功响应不再触发跳转。测试:store 两项(目录页、阅读页在响应到达前关闭 → 不写回、不重启轮询)与组件一项(提交中离开后不跳转),均在整改前代码上失败。
R4 / P2 重试后静默刷新失败会永久停在 failed
结论:确认成立。
retryChapter没有应用重试返回的状态,静默刷新吞掉异常且不安排轮询,一次网络抖动就会让页面停在处理失败。修复:重试被接受后先把返回的 pending 状态应用到章节列表与阅读器并重新安排轮询,再做静默刷新。
测试:store 两项(阅读页、书籍页:POST 成功 + 首次 GET 失败 + 网络恢复后自动显示就绪),整改前失败。
真实联调:用 SQL 制造真实失败任务(
content_changed)后,在浏览器点击“重试”并中断紧随其后的第一次刷新,页面立即由“处理失败”变为“处理中”,随后自行变为“已就绪”,无需手工刷新。回归测试的有效性(整改前实际失败)
7 项新增前端用例在整改前的
library.ts/ImportView.vue上运行并实际失败:追加发送 language、目录页/阅读页晚到响应写回、阅读页/书籍页重试后停在失败、组件级追加请求体、提交中离页后跳转;改回修复版本后 38 项全部通过。后端两项新用例覆盖运行期恢复与尝试上限。测试命令与结果
python scripts/server.py test-integration(LEXGO_TEST_DB_NAME=lexgo_test_issue5)npx --yes pnpm@9.15.1 --dir learner test:unit --runnpx --yes pnpm@9.15.1 --dir learner buildnpx --yes pnpm@9.15.1 --dir learner test:e2epython -m unittest discover -s tests/harness.py check --strict需要主审与用户知晓的契约变化
POST /api/v1/books/:id/chapters不接受language(发送即 400);追加沿用书籍语言。attempts_exhausted。POST /jobs/:id/retry)会把尝试次数重置为 0,并保留原章节与任务编号。未验证与限制
文档
Wiki 先写后回读,再导出核心镜像(镜像含于提交
b18f9cc):f981b86a7c6e5d2e353142d3006dcd6e0636c3ee4bd843d1f0134f5688407b7072d98333b40b6da13bce5fae964b1050513c37319262679814d68f14本地验证页同时记录了 MySQL 会话时区为 SYSTEM(本机 UTC+8)而服务按 UTC 存储 DATETIME 的差异:核对任务时间需用
UTC_TIMESTAMP,用NOW()会产生 8 小时假偏差(我自己第一次构造 R2 场景时就踩到,已更正后复测)。状态保持待验收,未关闭工单,交回主审独立检查与复测。
#5 整改独立复审(2026-09-11)
审核提交:b18f9cc,相对
a55708c的 11 个文件变更;已核对 PR #23 的当前提交与本地一致,工作区干净。结论:R1~R4 的修复合理,本轮未发现阻止提交用户验收的新问题。在当前单实例、同一 worker 串行清扫和处理的前提下,可以进入用户验收;这不代替用户验收,工单保持 open,PR 不合并。
本轮独立验证:专用 lexgo_test_issue5 上 Go 全包 20 项顶层用例通过;独立前端审查执行 38 项单测和 vue-tsc/Vite 构建,均通过。已核查新增回归用例,不只依据上一条交付声明。
说明与非阻塞建议:
未修改产品代码、未合并 PR、未关闭工单。长期事实无新增变化,本次只追加复审证据,不更新 Wiki。
工具回退沿用本单记录:Gitea MCP 指向不同站点,使用目标 git.ilapage.cn 的既有安全配置调用 API。
#5 用户确认结单(2026-09-11)
在主审报告 R1~R4 技术复审通过、可进入用户验收后,用户回复“可以结单吗”,本次按该确认结单。
验收版本:b18f9cc4a54dfb7ef4fe9f882a1b4d6a10c27997。实施与整改证据见评论 7651、7677,独立复审见评论 7686:Go 20 项顶层测试、前端 38 项单测及构建通过。
确认关闭本单;不宣称用户已另行执行完整手工测试。R3 真实浏览器竞态和 #4 真机详细证据仍未补齐,保留未验证说明;手机相关完整证据在后续体验/交付工作继续验证。正文最后一项包含手机验收,保持未勾选,避免把未验证内容标为通过。后续书库分页/截断提示与目录查询优化由 #24 跟踪。
本次仅更新工单验收状态与父单 #16 进度;不合并 PR #23 或其他 PR,不自动实施 #6/#21/#24,不改动产品代码和数据库。无新增长期技术契约,不修改 Wiki。Gitea API 回退原因沿用本单记录:MCP 指向其他站点。