Parcourir la source

docs: diagnose reading answer bias and plan consistent presentation

彭峰 il y a 5 heures
Parent
commit
5674faec4a
1 fichiers modifiés avec 120 ajouts et 0 suppressions
  1. 120 0
      docs/superpowers/plans/2026-11-15-reading-answer-distribution.md

+ 120 - 0
docs/superpowers/plans/2026-11-15-reading-answer-distribution.md

@@ -0,0 +1,120 @@
+# 阅读理解答案位置异常:排查与解决方案
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** 消除阅读试卷正确答案集中在 A 的问题,并确保在线答题、打印试卷、答案解析使用一致的选项对应关系。
+
+**Architecture:** 通过共享的、可复现的题组呈现函数控制正确选项位置,移动整个选项对象,保持正确内容及判分依据不变。在线答题和 PDF 使用同一个呈现版本;同时消除生成示例中的首项正确偏置,并处理解析里引用的原选项字母。首期兼容已有题目,不批量改写历史题目或成绩。
+
+**Tech Stack:** Angular 18、TypeScript、Jasmine/Karma、现有 Parse 阅读接口。
+
+**Spec:** 本文“调查结论”“目标与约束”是本方案的依据。当前用户请求为先查原因、再制定方案;本文任务均尚未实施。
+
+## 调查结论
+
+### 线上只读证据
+
+核查截止:2026-11-15 18:05(Asia/Shanghai)。统计按北京时间自然日筛选 `createdAt`,不是服务器默认时区。
+
+| 范围 | 阅读题数 | 关联文章/题组数 | 原始顺序正确答案 A/B/C/D | 五题全 A 题组 |
+| --- | ---: | ---: | --- | ---: |
+| 11 月 15 日截至核查时 | 105 | 21 | 104 / 1 / 0 / 0 | 20 |
+| 11 月 14 日全天 | 110 | 22 | 110 / 0 / 0 / 0 | 22 |
+
+- 今天的 21 组都有五个不同题号;105 道题均有四个不同选项、唯一 `check=true`,未标记删除。已单独回查关联文章,确认 21 篇存在。
+- 今天查询到的 `SurveyLog(type=exam)` 为 0;该结果仅说明未查到这种线上提交记录,不能据此判断学生未做纸质试卷,也不能证明用户反馈一定来自打印入口。
+- 今天至少 25 道题的题目级解析含显式的选项字母引用,如“B项张冠李戴,C项无中生有,D项时间倒置”。数字为规则命中数,不宣称覆盖全部自然语言引用。
+- 已抓取正式 H5 入口并沿依赖检查 63 个脚本,确认下面三处行为存在于当前线上产物,而非仅存在于本地源码。
+- 所有生产请求均为 GET;未生成新题、修改提示词、提交答案或调整成绩。私有证据存放于 `/Users/mac/.local/state/xiaoshu/qa/2026-11-15-reading-answer-audit/`,原始题目和线上代码不进入 Git。
+
+### 原因链路
+
+1. **生成格式示例有明显的首项偏置。** `english-reading.service.ts:153–159` 为每道题都生成 `check: optionIndex === 0` 的示例;`fmode-ai.service.ts` 将这个示例追加到提示词末尾,并要求严格按结构返回。正式产物 `chunk-62Y437QX.js` 同样存在 `check:m===0`。这是强烈的首项示范偏置;本次未做在线模型对照实验,因此不能把模型内部因果量化为已独立证明。
+2. **程序没有纠正或校验答案位置分布。** `createQuestions()` 检查数量、题目重复、四个不同选项和唯一正确项,然后把 `item.options` 按原顺序保存。线上网关 `readingCreate()` 也按传入数组保存,没有补做位置分散。
+3. **打印入口直接展示原始顺序。** `reading-pdf.component.ts:65–68` 取回题目后直接 `questions.set(questions)`;模板把数组第 0 项显示成 A。正式产物 `chunk-NPVFXZFL.js` 行为相同。因此数据库第一项正确会稳定成为打印的 A。
+4. **在线页与打印页存在两套顺序。** 在线初次加载及“再做一次”都会打乱题目、选项;正式产物 `chunk-KSDV6NJ6.js` 也如此。因此现有证据可以直接解释打印/PDF 全 A,但不足以断言在线按钮显示一定全 A。若用户反馈来自在线按钮,须补查具体文章与客户端版本;若来自解析文字,则需重点核对第 5 点。
+5. **解析文字没有随选项移动。** 在线页直接显示 `question.answer` 和 `option.answer`,其中 A/B/C/D 的文字仍指原顺序。单纯新增洗牌会扩大这个既有错位风险。
+
+线上 `PromptTemplate` 已写明“正确选项随机分布(避免固定位置模式)”,最后更新于 2026-09-04。故“再加一句随机要求”不能构成可靠修复。11 月 14 日已出现同样分布,不能归因于今天的新发布。
+
+### 本地复现与边界
+
+读取今天一组真实的五道题,使用项目实际 `reading.utils.ts` 经 TypeScript 转译后的校验与洗牌函数:
+
+- 现有完整性检查通过,PDF 原顺序答案为 `A A A A A`。
+- 按在线页现有处理方式运行 100 次,500 道题的正确位置分布为 `117 / 114 / 139 / 130`,该轮无全 A 题组。
+- 原始题目未被修改,所有正确选项内容保持一致。
+
+这是代码级复现,未冒充浏览器或实体手机验收;也未逐题审查 AI 答案的教学正确性。不能用“位置异常”推导全部答案内容错误或历史成绩算错。
+
+## 目标与约束
+
+- 推荐对每套五题采用随机化的近均衡分布:A/B/C/D 各至少一次,额外一次随机分配;题序与位置不按固定 ABCD 循环。
+- 字母只是显示编号,正确性始终跟随选项内容及 `check`,禁止仅修改正确答案字母或互换 `check`。
+- 首次打开、刷新、PDF 预览、导出必须能复现同一版题序和选项顺序;“再做一次”可生成新版本,打印跟随该版本。
+- 已有题目无需重生成;历史作答仍按题目 ID 与所选内容恢复,保留成绩和文章。已下载或已打印的旧 PDF 无法被远程更新,需重新导出。
+- 原始选项顺序保留用于解释旧解析的字母;正常英文单词、`Plan A`、文章中人名首字母不被误改。
+- 不完整题组继续使用现有保护,不静默补题后覆盖已完成记录。
+- 本次只产出调查和方案;实施阶段再运行以下开发与发布步骤。
+
+## Review Focus
+
+1. 旧题解析里的字母引用,以及无法无歧义识别的自然语言引用。
+2. “再做一次”、刷新、直接打开 PDF、返回在线页时的版本一致性。
+3. 历史成绩恢复、未答完重试、缺题、重复选项与多正确项。
+4. 选项内容依赖位置,如“Both A and B”“以上各项”,不能直接移动导致语义改变。
+5. 云端模板优先于内置模板、旧客户端缓存仍可能继续输出偏置数据。
+
+## 实施任务
+
+### 1. 统一题组呈现与解析映射
+
+**Files:** 新建 `projects/xiaoshu-mobile/src/app/features/english-reading/reading-presentation.ts` 及对应 `.spec.ts`。
+
+**Interfaces:**
+- `presentReadingQuestions(questions: ReadingQuestion[], seed: string): ReadingQuestion[]`:复制输入,校验完整题组,根据种子产生题序和近均衡位置,移动完整选项对象。
+- `remapReadingExplanation(text: string, labels: Readonly<Record<string, string>>): string`:仅映射无歧义选项引用;从原数组索引构造旧字母→新字母映射,单次替换,防止 A→B→C 的级联误替换。
+
+- [ ] 写失败测试:五题原始全 A;同一种子结果稳定;不同种子可产生不同结果;每个字母出现 1–2 次;正确内容、选项解析绑定和原始输入保持不变。
+- [ ] 写失败测试:`A项/B项/选项A/option A` 同步映射;`Plan A` 与普通单词保留;题目和各选项的解析都处理。
+- [ ] 写失败测试:不完整、重复内容、多正确项拒绝进入新题组编排;检测位置依赖选项,不直接重排导致含义变化。
+- [ ] 实现共享函数。对不能可靠转换的旧解析或位置依赖题逐题列入复核,不能用宽泛正则改写所有 A/B/C/D,也不能静默删除解释。
+- [ ] 运行专项测试并检查上述不变量后提交本任务文件。
+
+### 2. 在线练习与 PDF 共用呈现版本
+
+**Files:** 修改 `reading-exercise.component.ts`、`reading-pdf.component.ts`、`reading.models.ts`、`reading.utils.ts` 及相应测试;均位于上述 `english-reading` 目录。
+
+**Interfaces:** 路由增加非敏感 `presentationVersion`(默认 `v1`);共享种子由文章 ID 与该版本组成。使用任务 1 的 `presentReadingQuestions()`,不再在两个组件内各自安排选项。
+
+- [ ] 写失败测试:同一文章同一版本的在线页、PDF 题目区、PDF 答案区逐题逐选项相同;直接进入未带版本的 PDF 使用默认版本。
+- [ ] 写失败测试:“再做一次”建立新版本,写入当前路由并在打印/返回时携带;刷新不改变当前顺序;切换文章不沿用上一文章答题内容。
+- [ ] 写失败测试:历史 `answer` 按题目 ID 和内容恢复,计算成绩与原结果一致;缺题保护与保存失败重试保持正确。
+- [ ] 接入共享呈现函数和版本参数,继续按内容保存答案,不修改历史 `SurveyLog` 数据。
+- [ ] 专项测试通过后提交;使用真实题目脱敏夹具在浏览器核对在线与 PDF,覆盖至少一组全 A 和一组含字母解析的旧题。
+
+### 3. 消除生成示例偏置并加强校验
+
+**Files:** 修改 `english-reading.service.ts`、`reading-prompts.ts` 及相应测试。云端 `PromptTemplate` 更新通过独立、单记录、带旧值校验的发布步骤执行,不运行会从旧源覆盖全部模板的同步脚本。
+
+**Interfaces:** 保留现有题目 JSON 字段与接口;新生成题的题干、选项及解释以内容指代答案,不引用会随重排改变的选项字母和位置。
+
+- [ ] 写失败测试:格式示例不再每题固定首项 `true`;云端模板存在和缺失两条路径都附加“解释不依赖选项字母/位置”的要求。
+- [ ] 写失败测试:仅补齐缺失题目、生成重试、保存失败重试不会修改已有题目或破坏五题完整性。
+- [ ] 修改示例使用不同正确位置,校验生成结果里的位置引用。格式示例只能降低偏置,最终呈现分布由任务 1 保证。
+- [ ] 同步调整内置提示词,并准备云端该条模板的精确补丁和回滚副本;发布前核对模板 `updatedAt` 与旧内容,避免覆盖他人更新。
+- [ ] 专项测试通过后提交,保存脱敏生成样本核对内容正确性及解析独立性。
+
+### 4. 验收与发布
+
+- [ ] 专项测试:`npm run test:mobile:ci -- --include='projects/xiaoshu-mobile/src/app/features/english-reading/**/*.spec.ts'`,全部通过。
+- [ ] 全量移动端回归:`npm run test:mobile:ci`;构建:`npm run build:mobile`,均通过。
+- [ ] 把今天 21 套题作为私有只读样本验证:每套呈现后无全 A,四个位置分布符合约束,正确内容与原始 `check` 一致;含字母解析及位置依赖项逐题复核。
+- [ ] 浏览器验收在线选择、提交、历史恢复、再做、刷新、预览和 PDF 导出;提交测试使用专用隔离记录,不冒用真实学生成绩。PDF 逐页检查题目、答案和解析,完成至少一次实体手机/微信环境确认再报告相应覆盖。
+- [ ] 以发布时实际线上版本为基线,仅发布阅读改动,不能重新带入此前已回滚的性能候选。备份入口、资源与该条模板后进行发布和 CDN 版本核验。
+- [ ] 上线后只读观察新生成/呈现题组与错误日志;区分“原始生成位置统计”和“实际呈现位置统计”,不能用前者误判新展示修复失败。
+- [ ] 若需回滚,恢复本次前端入口及此次模板补丁;不回滚学生业务数据。先核对线上仍是本次发布,避免覆盖后续发布。
+
+## 完成判据
+
+相同版本的在线页、PDF 题目和答案逐项一致;五题正确位置符合约束;重排前后正确内容、历史选中内容和成绩一致;所有解析字母指向当前展示选项;旧题得到兼容;专项、全量和浏览器验收均有证据。当前仅调查与方案完成,以上修复与验收尚未执行。