MVP 完成章节并查看个人基础进度 #13

Closed
opened 2026-09-10 17:09:25 +08:00 by ila · 4 comments
Owner

来源与目标

2026-09-10 用户确认 F01–F12、原型通过,并要求按四阶段建议推进。原型验收:#1 评论 7498。阶段 4;覆盖 F11。

学习者完成章节后查看已读、已知词与待复习等基本数量,重复操作不重复计数。

验收标准

  • 完成章节只记已读,不批量改变词语等级;统计含义及已知/忽略区分明确。
  • 重复请求、切换账号与章节编辑/删除后计数一致,统计查询按本人和语言过滤。
  • 到期数量使用同一时钟/规则;固定数据验证页面数字与实际记录一致。
  • 不包含目标、日历和难度评分。

依赖与执行

前置:#10, #8, #11。状态:待验收(2026-09-15,提交 a9952b3,PR #33;契约见评论 8022,实施证据见最新评论)。前置尚未通过时不得标进行中;每单完成停在待验收,由用户验收后关闭。技术验证可与不依赖其结论的工作分工,但不提前冻结未验证契约。

参考模块与设计证据

领域统计查询;go-admin 看板样式仅参考,不引入现有无关管理指标。

沿用已验收章节完成和进度页面。

后端不为建表/API 单独画页面原型;先写数据、接口、状态、隔离与幂等契约。学习端采用 #1 已验收 v1,未做的 LinguaCafe 对照不标完成。

工作量、范围与风险

预计 2~3 人日(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 用户确认 F01–F12、原型通过,并要求按四阶段建议推进。原型验收:#1 评论 7498。阶段 4;覆盖 F11。 学习者完成章节后查看已读、已知词与待复习等基本数量,重复操作不重复计数。 ## 验收标准 - [ ] 完成章节只记已读,不批量改变词语等级;统计含义及已知/忽略区分明确。 - [ ] 重复请求、切换账号与章节编辑/删除后计数一致,统计查询按本人和语言过滤。 - [ ] 到期数量使用同一时钟/规则;固定数据验证页面数字与实际记录一致。 - [ ] 不包含目标、日历和难度评分。 ## 依赖与执行 前置:#10, #8, #11。状态:待验收(2026-09-15,提交 a9952b3,PR #33;契约见评论 8022,实施证据见最新评论)。前置尚未通过时不得标进行中;每单完成停在待验收,由用户验收后关闭。技术验证可与不依赖其结论的工作分工,但不提前冻结未验证契约。 ## 参考模块与设计证据 领域统计查询;go-admin 看板样式仅参考,不引入现有无关管理指标。 沿用已验收章节完成和进度页面。 后端不为建表/API 单独画页面原型;先写数据、接口、状态、隔离与幂等契约。学习端采用 #1 已验收 v1,未做的 LinguaCafe 对照不标完成。 ## 工作量、范围与风险 预计 2~3 人日(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 回退;凭据仅进入进程。
Author
Owner

#13 方案确认与实施启动(2026-09-15)

用户 2026-09-15 指示「做 #13,都按你说的来做」,授权按本契约实施。覆盖 F11(完成阅读与基础进度),前置 #10、#8、#11 均已验收关闭。分支 feat/13-progress 从 main f2de395 创建。

D1 数据:schema v7 新增 lexgo_chapter_progress

新表而不是给 lexgo_chapters 加列。本项目每个版本的 DDL 都是可重放的 CREATE TABLE IF NOT EXISTS,ALTER TABLE ADD COLUMN 不可重放,会破坏已测属性「回滚标记 → 重新升级仍可用」(#11 D3 的结论)。

列 说明
chapter_id 主键,一章一行,天然满足「重复完成不重复计数」
owner_id, book_id, language 归属与范围过滤,均带外键(章节或账号删除时级联)
read_sha256 标记时该章 content_sha256 的快照,用于内容版本门控
read_at, created_at, updated_at 时间戳(UTC 毫秒截断,与既有约定一致)

D2 接口

接口 行为与边界
POST /api/v1/chapters/:id/complete 标记本章已读;只有 ready 章节可标记(否则 409);重复调用返回同一行并带 duplicate=true,不重复计数;他人或不存在 404;未登录 401
GET /api/v1/progress 返回本人当前语言的基础进度与每本书的已读进度

D3 计数口径(明确写进 Wiki)

  • 已读章节 = progress 行的 read_sha256 等于该章当前 content_sha256,且章节 ready、所属书语言=本人空间语言。因此编辑正文后该章自动回到未读(重新标记即更新同一行),只改标题不清除,删除章节随级联消失。
  • 分母 totalChapters = 同一范围内 ready 的章节数;处理中或失败的章节不计入分母,界面写「已读章节 3 / 8 章(可阅读)」把规则显示出来。
  • 已知 / 学习中 / 新词 / 忽略分别计数,不合并;savedTerms 为本人该语言全部词条(含忽略)。已知与忽略分开统计,符合业务规则第 2 条。
  • dueNow 与到期复习队列共用同一查询构造与同一服务端时钟(status ∈ 新词/学习中 且 due_at ≤ now),避免两处漂移;集成测试会断言 dueNow 与 GET /reviews/queue 的 total 一致。
  • 全部统计按本人与本人语言过滤;管理员权限不放宽归属。

D4 完成入口

阅读页正文末尾一个显式按钮「标记本章已读」,不做滚动到底自动标记;已读时显示已读时间;不做「取消已读」(增强项,正文版本变化会自然回到未读);不批量修改词语等级(X10 不做)。书籍页章节列表对已读章节显示标记。

D5 进度页面

新增 /progress 与导航「进度」:已读章节、已知词、待复习、学习中、新词、忽略、已保存词条,加每本书的已读进度与进入书籍的链接;没有书时引导导入。不含每日目标、日历、难度评分(工单明确排除)。

D6 前端状态

新增 stores/progress.ts(加载、失败、代次校验、账号切换重置),stores/library.ts 增加 markChapterRead,并把已读状态合并进阅读与书籍页。

D7 范围外

X10 批量标已知、每日目标/日历/难度、复习范围筛选(X11)、撤销已读、统计导出、CSV(X04)。

D8 验证

Go 集成(测试库 lexgo_test_issue13):重复标记幂等、正文新版本回到未读、只改标题保持已读、章节删除后计数、非 ready 409、他人与不存在 404、未登录 401、计数与复习队列一致、按本人与语言隔离、迁移 v6→v7 与「回滚标记后重新升级」。前端单测与 E2E 覆盖标记、列表标记、进度页数字与空状态。真实 API+MySQL 额外用 SQL 直查与接口数字比对,满足「固定数据验证页面数字与实际记录一致」。

D9 文档与迁移

更新 Architecture-and-Code-Map、Business-Rules-and-Glossary、Local-Development-and-Verification、Product-Requirements-Overview 与 Home。开发库需显式 python scripts/server.py migrate(v6→v7),迁移测试只能用 lexgo_test_ 前缀专用库。

D10 回退

备份二进制 .local/lexgo-pre-issue13.exe;回退时把 lexgo_schema.version 写回 6 并丢弃新表即可,业务数据不受影响。

Gitea MCP 仍指向其他站点,沿用目标站点 API 回退并在此记录;凭据仅从既有安全配置读入进程。

## #13 方案确认与实施启动(2026-09-15) 用户 2026-09-15 指示「做 #13,都按你说的来做」,授权按本契约实施。覆盖 F11(完成阅读与基础进度),前置 #10、#8、#11 均已验收关闭。分支 `feat/13-progress` 从 main `f2de395` 创建。 ### D1 数据:schema v7 新增 lexgo_chapter_progress 新表而不是给 `lexgo_chapters` 加列。本项目每个版本的 DDL 都是可重放的 `CREATE TABLE IF NOT EXISTS`,`ALTER TABLE ADD COLUMN` 不可重放,会破坏已测属性「回滚标记 → 重新升级仍可用」(#11 D3 的结论)。 | 列 | 说明 | |---|---| | chapter_id | 主键,一章一行,天然满足「重复完成不重复计数」 | | owner_id, book_id, language | 归属与范围过滤,均带外键(章节或账号删除时级联) | | read_sha256 | 标记时该章 `content_sha256` 的快照,用于内容版本门控 | | read_at, created_at, updated_at | 时间戳(UTC 毫秒截断,与既有约定一致) | ### D2 接口 | 接口 | 行为与边界 | |---|---| | POST /api/v1/chapters/:id/complete | 标记本章已读;只有 `ready` 章节可标记(否则 409);重复调用返回同一行并带 `duplicate=true`,不重复计数;他人或不存在 404;未登录 401 | | GET /api/v1/progress | 返回本人当前语言的基础进度与每本书的已读进度 | ### D3 计数口径(明确写进 Wiki) - **已读章节** = progress 行的 `read_sha256` 等于该章当前 `content_sha256`,且章节 `ready`、所属书语言=本人空间语言。因此**编辑正文后该章自动回到未读**(重新标记即更新同一行),只改标题不清除,删除章节随级联消失。 - **分母 totalChapters** = 同一范围内 `ready` 的章节数;处理中或失败的章节不计入分母,界面写「已读章节 3 / 8 章(可阅读)」把规则显示出来。 - **已知 / 学习中 / 新词 / 忽略**分别计数,不合并;**savedTerms** 为本人该语言全部词条(含忽略)。已知与忽略分开统计,符合业务规则第 2 条。 - **dueNow** 与到期复习队列**共用同一查询构造与同一服务端时钟**(`status ∈ 新词/学习中` 且 `due_at ≤ now`),避免两处漂移;集成测试会断言 `dueNow` 与 `GET /reviews/queue` 的 `total` 一致。 - 全部统计按本人与本人语言过滤;管理员权限不放宽归属。 ### D4 完成入口 阅读页正文末尾一个**显式**按钮「标记本章已读」,不做滚动到底自动标记;已读时显示已读时间;不做「取消已读」(增强项,正文版本变化会自然回到未读);不批量修改词语等级(X10 不做)。书籍页章节列表对已读章节显示标记。 ### D5 进度页面 新增 `/progress` 与导航「进度」:已读章节、已知词、待复习、学习中、新词、忽略、已保存词条,加每本书的已读进度与进入书籍的链接;没有书时引导导入。不含每日目标、日历、难度评分(工单明确排除)。 ### D6 前端状态 新增 `stores/progress.ts`(加载、失败、代次校验、账号切换重置),`stores/library.ts` 增加 `markChapterRead`,并把已读状态合并进阅读与书籍页。 ### D7 范围外 X10 批量标已知、每日目标/日历/难度、复习范围筛选(X11)、撤销已读、统计导出、CSV(X04)。 ### D8 验证 Go 集成(测试库 lexgo_test_issue13):重复标记幂等、正文新版本回到未读、只改标题保持已读、章节删除后计数、非 ready 409、他人与不存在 404、未登录 401、计数与复习队列一致、按本人与语言隔离、迁移 v6→v7 与「回滚标记后重新升级」。前端单测与 E2E 覆盖标记、列表标记、进度页数字与空状态。真实 API+MySQL 额外用 SQL 直查与接口数字比对,满足「固定数据验证页面数字与实际记录一致」。 ### D9 文档与迁移 更新 Architecture-and-Code-Map、Business-Rules-and-Glossary、Local-Development-and-Verification、Product-Requirements-Overview 与 Home。开发库需显式 `python scripts/server.py migrate`(v6→v7),迁移测试只能用 lexgo_test_ 前缀专用库。 ### D10 回退 备份二进制 `.local/lexgo-pre-issue13.exe`;回退时把 `lexgo_schema.version` 写回 6 并丢弃新表即可,业务数据不受影响。 Gitea MCP 仍指向其他站点,沿用目标站点 API 回退并在此记录;凭据仅从既有安全配置读入进程。
Author
Owner

#13 实施完成,待用户验收(2026-09-15)

用户 2026-09-15 指示「做 #13,都按你说的来做」,按契约评论 8022 实施。分支 feat/13-progress 从 main f2de395 创建,功能提交 a9952b3 已推送;PR #33 未合并,工单不关闭,停在待用户验收。

实现与差异

  • D1 schema v7:新表 lexgo_chapter_progress(chapter_id 主键、owner_id、book_id、language、read_sha256、read_at 与时间戳;外键级联章节、书籍、账号)。仍然只用可重放的 CREATE TABLE IF NOT EXISTS,不用 ALTER TABLE ADD COLUMN。
  • D2 接口:POST /api/v1/chapters/:id/complete 与 GET /api/v1/progress,server/app/lexgo/progress.go。
  • D3 口径:已读与分母都只算 ready 章节;完成记录保存标记时的 content_sha256,正文新版本后该章回到未读(记录保留,重读后更新同一行),只改标题不影响;已知/学习中/新词/忽略分别计数;dueNow 与复习队列共用新抽出的 dueTermsQuery 与同一服务端时钟。
  • D4 完成入口:阅读器正文下方显式「标记本章已读」区块(不改词语状态、不自动标记、不做取消已读);书籍页章节列表显示「已读」。
  • D5 进度页面:/progress 与导航「进度」,六张统计卡 + 每本书的已读进度 + 已保存词条 + 空态与失败重试;无目标、日历与难度评分。
  • D6 前端状态:stores/progress.ts(代次校验、账号切换重置、失败保留旧数据)、stores/library.ts 的 markChapterRead。

实际验证

验证 结果
go vet ./... 通过
LEXGO_TEST_DB_NAME=lexgo_test_issue13 python scripts/server.py test-integration 70 个顶层用例全部通过、0 跳过(基线 main 67;新增 3 个用例)
learner npx vitest --run / vue-tsc --build / pnpm run build / playwright test 130 项单测、类型检查、构建、15 项 E2E 通过(新增 10 单测与 2 项 E2E)
admin pnpm test / pnpm lint 31 项与 lint 通过;管理端无改动
python -m unittest discover -s tests / harness.py check --strict / sync --check 56 项、严格检查、镜像一致
真实 API+MySQL 37 项检查通过(可重复运行,自建 fixture 并清理)
真实浏览器 粘贴章节 → 处理完成 → 标记已读 → 书籍列表显示已读 → 进度页数字 → 刷新一致 → 再次标记不重复计数 → 清理 fixture

覆盖:完成幂等(不移动时间、只有一行)、非 ready 409、越权与未登录、阅读器/列表已读状态一致、正文新版本回到未读、只改标题保持已读、章节删除后计数与记录同时消失、四种词条状态分别计数、dueNow 与队列 total 一致、每本书进度、账号与语言隔离、迁移 v6→v7 与回滚重升级、新表唯一性与级联。页面数字与 SQL 直查逐项比对全部相等(已读/可读章节、待复习、四种状态、已保存总数),满足「固定数据验证页面数字与实际记录一致」。

迁移证据:开发库 lexgo_dev 迁移前后逐表计数完全一致,schema 6→7(.local/issue13-before.json、.local/issue13-after.json);本机 lexgo-api 已用新二进制重启(v7),/healthz 200;回退二进制 .local/lexgo-pre-issue13.exe。

顺带记录的既有缺陷(不在本单范围)

真实验证时发现并已单独建单:#32 编辑章节正文回到曾经用过的版本会返回 500。根因是 edit.go 用 edit:<章节>:<内容摘要> 派生任务键,与 lexgo_ingest_jobs 唯一键冲突(MySQL 1062 → 通用 500,事务整体回滚、数据不损坏)。已在 #32 给出稳定复现(A→B→A→B)与两个候选修复方向,本单未修改该代码;本单的真实验证脚本因此改为自建 fixture 书籍、不改写既有正文。请用户决定是否排期与选择方案(方案 1 需要 schema 变更)。

未验证与边界

  • 真实手机触屏与滚动证据仍属既有缺口(#14 承接)。
  • 进度页按书籍编号列出,没有排序与搜索;未做大数据量统计性能压测。
  • 不含每日目标、日历、难度评分、统计导出与取消已读;不含 X10 批量标已知与 X11 复习范围筛选。

文档

  • Architecture-and-Code-Map: 9bc2de753de2249c586306cdc27b566052941da2
  • Business-Rules-and-Glossary: 67b43213bdbf87c5af03c324d40ccc1b37a11ea6
  • Local-Development-and-Verification: 8222610b19a406a74771ded2f3edfa94a69f6295
  • Product-Requirements-Overview: abf6629dfe44d838dd235b11543d9fdf94429899
  • Home: 9ee88d82494e22e689086b053770c4f4620d3657
  • 镜像校验:sync --check 通过,另对 4 个变更页做逐字节正文比对(全部一致)
  • 仓库根 AGENTS.md 与 README.md 已同步口径与进度

回退

把 lexgo_schema.version 写回 6、丢弃 lexgo_chapter_progress,并恢复 .local/lexgo-pre-issue13.exe 后重启 lexgo-api;既有书籍、词条、复习记录不受影响。

Gitea MCP 仍指向其他站点,沿用目标站点 API 回退;凭据仅从既有安全配置读入进程。

附件:issue13-reader-unread/read、issue13-progress(mock 浏览器流程)与 issue13-real-reader-unread/read、issue13-real-progress(真实 API+MySQL 链路);本会话模型不能读取图片,功能断言来自程序化检查与 SQL 比对。

## #13 实施完成,待用户验收(2026-09-15) 用户 2026-09-15 指示「做 #13,都按你说的来做」,按契约评论 [8022](https://git.ilapage.cn/OPC/lexgo/issues/13#issuecomment-8022) 实施。分支 `feat/13-progress` 从 main `f2de395` 创建,功能提交 `a9952b3` 已推送;PR [#33](https://git.ilapage.cn/OPC/lexgo/pulls/33) 未合并,工单不关闭,停在待用户验收。 ### 实现与差异 - **D1 schema v7**:新表 `lexgo_chapter_progress`(`chapter_id` 主键、`owner_id`、`book_id`、`language`、`read_sha256`、`read_at` 与时间戳;外键级联章节、书籍、账号)。仍然只用可重放的 `CREATE TABLE IF NOT EXISTS`,不用 `ALTER TABLE ADD COLUMN`。 - **D2 接口**:`POST /api/v1/chapters/:id/complete` 与 `GET /api/v1/progress`,`server/app/lexgo/progress.go`。 - **D3 口径**:已读与分母都只算 `ready` 章节;完成记录保存标记时的 `content_sha256`,正文新版本后该章回到未读(记录保留,重读后更新同一行),只改标题不影响;已知/学习中/新词/忽略分别计数;`dueNow` 与复习队列共用新抽出的 `dueTermsQuery` 与同一服务端时钟。 - **D4 完成入口**:阅读器正文下方显式「标记本章已读」区块(不改词语状态、不自动标记、不做取消已读);书籍页章节列表显示「已读」。 - **D5 进度页面**:`/progress` 与导航「进度」,六张统计卡 + 每本书的已读进度 + 已保存词条 + 空态与失败重试;无目标、日历与难度评分。 - **D6 前端状态**:`stores/progress.ts`(代次校验、账号切换重置、失败保留旧数据)、`stores/library.ts` 的 `markChapterRead`。 ### 实际验证 | 验证 | 结果 | |---|---| | `go vet ./...` | 通过 | | `LEXGO_TEST_DB_NAME=lexgo_test_issue13 python scripts/server.py test-integration` | 70 个顶层用例全部通过、0 跳过(基线 main 67;新增 3 个用例) | | learner `npx vitest --run` / `vue-tsc --build` / `pnpm run build` / `playwright test` | 130 项单测、类型检查、构建、15 项 E2E 通过(新增 10 单测与 2 项 E2E) | | admin `pnpm test` / `pnpm lint` | 31 项与 lint 通过;管理端无改动 | | `python -m unittest discover -s tests` / `harness.py check --strict` / `sync --check` | 56 项、严格检查、镜像一致 | | 真实 API+MySQL | 37 项检查通过(可重复运行,自建 fixture 并清理) | | 真实浏览器 | 粘贴章节 → 处理完成 → 标记已读 → 书籍列表显示已读 → 进度页数字 → 刷新一致 → 再次标记不重复计数 → 清理 fixture | 覆盖:完成幂等(不移动时间、只有一行)、非 ready 409、越权与未登录、阅读器/列表已读状态一致、正文新版本回到未读、只改标题保持已读、章节删除后计数与记录同时消失、四种词条状态分别计数、`dueNow` 与队列 `total` 一致、每本书进度、账号与语言隔离、迁移 v6→v7 与回滚重升级、新表唯一性与级联。**页面数字与 SQL 直查逐项比对全部相等**(已读/可读章节、待复习、四种状态、已保存总数),满足「固定数据验证页面数字与实际记录一致」。 迁移证据:开发库 lexgo_dev 迁移前后逐表计数完全一致,schema 6→7(`.local/issue13-before.json`、`.local/issue13-after.json`);本机 lexgo-api 已用新二进制重启(v7),`/healthz` 200;回退二进制 `.local/lexgo-pre-issue13.exe`。 ### 顺带记录的既有缺陷(不在本单范围) 真实验证时发现并已单独建单:**#32 编辑章节正文回到曾经用过的版本会返回 500**。根因是 `edit.go` 用 `edit:<章节>:<内容摘要>` 派生任务键,与 `lexgo_ingest_jobs` 唯一键冲突(MySQL 1062 → 通用 500,事务整体回滚、数据不损坏)。已在 #32 给出稳定复现(A→B→A→B)与两个候选修复方向,**本单未修改该代码**;本单的真实验证脚本因此改为自建 fixture 书籍、不改写既有正文。请用户决定是否排期与选择方案(方案 1 需要 schema 变更)。 ### 未验证与边界 - 真实手机触屏与滚动证据仍属既有缺口(#14 承接)。 - 进度页按书籍编号列出,没有排序与搜索;未做大数据量统计性能压测。 - 不含每日目标、日历、难度评分、统计导出与取消已读;不含 X10 批量标已知与 X11 复习范围筛选。 ### 文档 - Architecture-and-Code-Map: `9bc2de753de2249c586306cdc27b566052941da2` - Business-Rules-and-Glossary: `67b43213bdbf87c5af03c324d40ccc1b37a11ea6` - Local-Development-and-Verification: `8222610b19a406a74771ded2f3edfa94a69f6295` - Product-Requirements-Overview: `abf6629dfe44d838dd235b11543d9fdf94429899` - Home: `9ee88d82494e22e689086b053770c4f4620d3657` - 镜像校验:`sync --check` 通过,另对 4 个变更页做逐字节正文比对(全部一致) - 仓库根 `AGENTS.md` 与 `README.md` 已同步口径与进度 ### 回退 把 `lexgo_schema.version` 写回 6、丢弃 `lexgo_chapter_progress`,并恢复 `.local/lexgo-pre-issue13.exe` 后重启 lexgo-api;既有书籍、词条、复习记录不受影响。 Gitea MCP 仍指向其他站点,沿用目标站点 API 回退;凭据仅从既有安全配置读入进程。 附件:issue13-reader-unread/read、issue13-progress(mock 浏览器流程)与 issue13-real-reader-unread/read、issue13-real-progress(真实 API+MySQL 链路);本会话模型不能读取图片,功能断言来自程序化检查与 SQL 比对。
Author
Owner

#13 代码审核:达标(2026-09-15,Claude Code)

审核对象:提交 a9952b3(PR #33)。只读审阅代码与测试差异,没有重跑测试。契约 D1~D10(评论 8022)逐条核对如下。

逐条核对

  • D1 schema v7:lexgo_chapter_progress 用 chapter_id 作主键(一章一行,天然幂等),read_sha256 做内容版本门控,外键级联章节/书籍/账号;仍是 CREATE TABLE IF NOT EXISTS。TestMigrationFromV6AddsChapterProgress 直接验证了「标记回退到 v6 再重新升级」不丢数据、唯一约束生效、删除章节级联清理——这正是 #11 用来否决 ALTER TABLE ADD COLUMN 方案的那条测试,这次一次性设计对了。达标。
  • D2 接口:CompleteChapter 在同一事务里锁章节、判断 ready、锁已有进度行、按 ReadSHA256 是否等于当前 ContentSHA256 决定是否已是同一次标记;重复调用返回 duplicate=true 且不移动时间;非 ready 409、他人/不存在 404、未登录 401 均由 TestMySQLChapterCompletionIsIdempotentAndContentBound 逐项覆盖,包括恶意边界(chapterId=0)。达标。
  • D3 计数口径:readAtByChapter/LearnerProgressFor 的已读判定都是 read_sha256 = content_sha256 AND status = ready,编辑正文后自动回到未读、只改标题保留标记、重新标记复用同一行(不新增),这四种情形分别有测试断言。已知/学习中/新词/忽略分类计数用一次 GROUP BY status 得出,不会互相合并;dueNow 通过把原来 ReviewQueueFor 内联的查询提取成 dueTermsQuery 共享给复习队列和进度页两处调用,我核对了 review.go 的这处重构,两处用的是同一个函数、同一个 now 参数,不是「分别实现、恰好结果一致」。TestMySQLProgressCountsMatchRecords 更进一步:用原始 SQL 直接对 lexgo_chapters/lexgo_chapter_progress 计数,与接口返回的数字逐项比对,同时验证 progress.DueNow 与 GET /reviews/queue 的 total 相等。达标,且验证方式比一般单测更严格。
  • D4 完成入口:不批量修改词语状态——CompleteChapter 全程只操作 ChapterProgress 表,没有触碰 Term/TermReview。达标。
  • D7 范围外:X10/X11/CSV 导出/撤销已读均未实现,也没有在代码里留半成品。达标。
  • D9 迁移:SchemaVersion 确认为 7,schemaV7Statements 是本次唯一新增的 DDL 语句。达标。

顺带发现的既有缺陷(#32)处理方式:符合流程

真实链路验证时发现「正文改回曾用过的版本会 500」,根因在 #10 的 edit.go 任务键派生逻辑,与本单无关。核对 edit.go 的 diff,本单只新增了 readAtByChapter 调用来解析编辑响应里的 readAt 字段,没有触碰任何任务键或版本门控逻辑;已确认过的工单 #32 有清晰的根因定位、最小复现步骤和两个候选方案,明确停在「待用户确认修复方案」,没有借这个机会顺手改掉。这是正确的处理方式——发现问题记录、不越界修复、等待确认。

结论

达标,可以进入用户验收。 这单在「同一份查询逻辑喂给两处界面」(dueTermsQuery)和「用原始 SQL 反向核对接口输出」两点上做得比前几单更严格,直接命中了验收标准里「固定数据验证页面数字与实际记录一致」和「到期数量使用同一时钟/规则」这两条不容易验证到位的要求。迁移测试复用了 #11 踩过的坑(重放性),说明确实吸收了之前的审核经验。

本次审核只读代码,没有重跑 test-integration(lexgo_test_issue13)与 learner 的 vitest/E2E;pi 报告的 70 项集成用例、130 项前端单测、迁移前后逐表计数比对等结果未被本次复核重复验证。

Gitea MCP 仍指向其他站点,本次沿用已记录的目标站点 API 回退;凭据只从 ~/.claude/gitea.env 安全配置读入进程。

## #13 代码审核:达标(2026-09-15,Claude Code) 审核对象:提交 `a9952b3`(PR #33)。只读审阅代码与测试差异,没有重跑测试。契约 D1~D10(评论 8022)逐条核对如下。 ### 逐条核对 - **D1 schema v7**:`lexgo_chapter_progress` 用 `chapter_id` 作主键(一章一行,天然幂等),`read_sha256` 做内容版本门控,外键级联章节/书籍/账号;仍是 `CREATE TABLE IF NOT EXISTS`。`TestMigrationFromV6AddsChapterProgress` 直接验证了「标记回退到 v6 再重新升级」不丢数据、唯一约束生效、删除章节级联清理——这正是 #11 用来否决 `ALTER TABLE ADD COLUMN` 方案的那条测试,这次一次性设计对了。**达标**。 - **D2 接口**:`CompleteChapter` 在同一事务里锁章节、判断 `ready`、锁已有进度行、按 `ReadSHA256` 是否等于当前 `ContentSHA256` 决定是否已是同一次标记;重复调用返回 `duplicate=true` 且不移动时间;非 `ready` 409、他人/不存在 404、未登录 401 均由 `TestMySQLChapterCompletionIsIdempotentAndContentBound` 逐项覆盖,包括恶意边界(`chapterId=0`)。**达标**。 - **D3 计数口径**:`readAtByChapter`/`LearnerProgressFor` 的已读判定都是 `read_sha256 = content_sha256 AND status = ready`,编辑正文后自动回到未读、只改标题保留标记、重新标记复用同一行(不新增),这四种情形分别有测试断言。已知/学习中/新词/忽略分类计数用一次 `GROUP BY status` 得出,不会互相合并;`dueNow` 通过把原来 `ReviewQueueFor` 内联的查询提取成 `dueTermsQuery` 共享给复习队列和进度页两处调用,我核对了 `review.go` 的这处重构,两处用的是同一个函数、同一个 `now` 参数,不是「分别实现、恰好结果一致」。`TestMySQLProgressCountsMatchRecords` 更进一步:用原始 SQL 直接对 `lexgo_chapters`/`lexgo_chapter_progress` 计数,与接口返回的数字逐项比对,同时验证 `progress.DueNow` 与 `GET /reviews/queue` 的 `total` 相等。**达标,且验证方式比一般单测更严格**。 - **D4 完成入口**:不批量修改词语状态——`CompleteChapter` 全程只操作 `ChapterProgress` 表,没有触碰 `Term`/`TermReview`。**达标**。 - **D7 范围外**:X10/X11/CSV 导出/撤销已读均未实现,也没有在代码里留半成品。**达标**。 - **D9 迁移**:`SchemaVersion` 确认为 7,`schemaV7Statements` 是本次唯一新增的 DDL 语句。**达标**。 ### 顺带发现的既有缺陷(#32)处理方式:符合流程 真实链路验证时发现「正文改回曾用过的版本会 500」,根因在 #10 的 `edit.go` 任务键派生逻辑,与本单无关。核对 `edit.go` 的 diff,本单**只**新增了 `readAtByChapter` 调用来解析编辑响应里的 `readAt` 字段,没有触碰任何任务键或版本门控逻辑;已确认过的工单 #32 有清晰的根因定位、最小复现步骤和两个候选方案,明确停在「待用户确认修复方案」,没有借这个机会顺手改掉。这是正确的处理方式——发现问题记录、不越界修复、等待确认。 ### 结论 **达标,可以进入用户验收。** 这单在「同一份查询逻辑喂给两处界面」(`dueTermsQuery`)和「用原始 SQL 反向核对接口输出」两点上做得比前几单更严格,直接命中了验收标准里「固定数据验证页面数字与实际记录一致」和「到期数量使用同一时钟/规则」这两条不容易验证到位的要求。迁移测试复用了 #11 踩过的坑(重放性),说明确实吸收了之前的审核经验。 本次审核只读代码,没有重跑 `test-integration`(`lexgo_test_issue13`)与 learner 的 vitest/E2E;pi 报告的 70 项集成用例、130 项前端单测、迁移前后逐表计数比对等结果未被本次复核重复验证。 Gitea MCP 仍指向其他站点,本次沿用已记录的目标站点 API 回退;凭据只从 `~/.claude/gitea.env` 安全配置读入进程。
Author
Owner

#13 验收通过(2026-09-15)

用户于 2026-09-15 明确回复「#13 通过验收」。

  • 验收范围:#13 契约 D1~D10(评论 8022)— 章节完成的幂等与「只记已读、不批量改变词语状态」、正文内容版本门控、进度页的已读/可阅读章节与四种词条状态、待复习与复习队列同规则同口径、每本书的已读进度、schema v7 新表与显式迁移。
  • 合并:PR #33 已 fast-forward-only 合入 main,merge commit a9952b3;验收文档提交 5f86f17 已推送。
  • 文档 revision:Home d40a8f10717a5d7bb7de58e5ee5fd4f56220cc86、Architecture 2cfb6d795ddea33cbb348c743a4928ec62b4678f、Product-Requirements f1f5f9729f30f6679b7fdbdd5bd6e0568a8688db、Project-Profile 0c0354499b49ef5973ffcdc47e9eba40f447536b。
  • 镜像校验:harness.py sync --check 通过,并对 4 个变更页做逐字节正文比对(全部一致)。站点对整页批量回读仍返回 HTTP 429,沿用「revision 级 check + 变更页正文比对」,回退原因记录于此。
  • 迁移与回退:本单 schema v7(新增 lexgo_chapter_progress),开发库迁移前后逐表计数一致;回退时把 lexgo_schema.version 写回 6、丢弃新表并恢复 .local/lexgo-pre-issue13.exe 重启 lexgo-api,业务数据不受影响。
  • 遗留:真实手机触屏与滚动证据仍由 #14 承接;进度页无排序与搜索,未做大数量性能压测。
  • 待用户决定:缺陷 #32(编辑章节正文回到曾用版本返回 500)已定位,修复方案 1 需要 schema 变更、方案 2 不需要,尚未排期。

单元工单关闭;#16 的 #13 复选框同步勾选。

## #13 验收通过(2026-09-15) 用户于 2026-09-15 明确回复「#13 通过验收」。 - 验收范围:#13 契约 D1~D10(评论 [8022](https://git.ilapage.cn/OPC/lexgo/issues/13#issuecomment-8022))— 章节完成的幂等与「只记已读、不批量改变词语状态」、正文内容版本门控、进度页的已读/可阅读章节与四种词条状态、待复习与复习队列同规则同口径、每本书的已读进度、schema v7 新表与显式迁移。 - 合并:PR [#33](https://git.ilapage.cn/OPC/lexgo/pulls/33) 已 fast-forward-only 合入 main,merge commit `a9952b3`;验收文档提交 `5f86f17` 已推送。 - 文档 revision:Home `d40a8f10717a5d7bb7de58e5ee5fd4f56220cc86`、Architecture `2cfb6d795ddea33cbb348c743a4928ec62b4678f`、Product-Requirements `f1f5f9729f30f6679b7fdbdd5bd6e0568a8688db`、Project-Profile `0c0354499b49ef5973ffcdc47e9eba40f447536b`。 - 镜像校验:`harness.py sync --check` 通过,并对 4 个变更页做逐字节正文比对(全部一致)。站点对整页批量回读仍返回 HTTP 429,沿用「revision 级 check + 变更页正文比对」,回退原因记录于此。 - 迁移与回退:本单 schema v7(新增 `lexgo_chapter_progress`),开发库迁移前后逐表计数一致;回退时把 `lexgo_schema.version` 写回 6、丢弃新表并恢复 `.local/lexgo-pre-issue13.exe` 重启 lexgo-api,业务数据不受影响。 - 遗留:真实手机触屏与滚动证据仍由 #14 承接;进度页无排序与搜索,未做大数量性能压测。 - 待用户决定:缺陷 #32(编辑章节正文回到曾用版本返回 500)已定位,修复方案 1 需要 schema 变更、方案 2 不需要,尚未排期。 单元工单关闭;#16 的 #13 复选框同步勾选。
ila closed this issue 2026-09-15 14:31:33 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/lexgo#13