{
  "head": "0baa9ebe8b7f9ecc46f675acbf1f56ac65378957",
  "old": "e9f2fb1b58a2a0292e5a95a9cbeb6fae7f956682",
  "master": "873c4f2d7c63a947216ae92bdc393b73408b6b6e",
  "findings": [
    {
      "id": "01",
      "p": 2,
      "title": "CSV未闭合引号仍吞后续短语，且修文件重导不能纠正已写错误译文",
      "scope": "05 / 07 / 08 import-publish",
      "file": "application/src/main/java/cn/jojo/cc/biz/service/english/dict/EnglishImportFileReader.java",
      "start": 363,
      "end": 365,
      "trigger": "短语文件 translation 开引号后直到EOF未闭合，后面还有正常记录。",
      "mechanism": "readRecords不检查EOF的inQuotes，直接addRecord；readPhrases将后续物理行作为允许换行的translation，rows有效且invalid为空。importOnePhrase正常创建后，重导因主词已存在直接skip。",
      "impact": "look up译文变成“查找\\nget up,起床”，get up整条丢失；修文件重导无法恢复look up已落的错误译文。",
      "fix": "EOF拒绝未闭合引号并记录起始物理行；同时约束引号只在字段边界出现。",
      "validation": "本轮原完整Reader/Normalizer与原Param javac隔离执行，见 evidence/import/results.txt",
      "evidence": "evidence/import/results.txt",
      "kind": "旧问题仍存（当前源码重新核实）",
      "counter_evidence": "无真实DB/MQ/外部调用；除明确标为本轮javac的项目，均为当前源码链路核对，不复用旧实跑作为当前实跑。",
      "previous_id": "01",
      "reviewer_id": "IP01"
    },
    {
      "id": "02",
      "p": 2,
      "title": "非法变形不应部分入库，避免幂等跳过堵死修文件重导",
      "scope": "05 / 07 / 08 import-publish",
      "file": "application/src/main/java/cn/jojo/cc/biz/service/english/dict/EnglishImportFileReader.java",
      "start": 171,
      "end": 173,
      "trigger": "同一短语variants有合法及非法文本：get up / got up|起床。",
      "mechanism": "非法项只continue内层循环；主短语和got up仍进入rows并写库。修成got up|gotten up重导时，importOnePhrase先getByNormalized命中已建主词而直接false。",
      "impact": "报告“变形非法”同时建成残缺语义；修文件重导仍无法加入gotten up，后续题面该变形漏短语命中。",
      "fix": "任一非空variant非法时整条短语不进入有效rows，保留行错误待修文件重导。",
      "validation": "本轮原完整Reader/Normalizer与原Param javac隔离执行，见 evidence/import/results.txt",
      "evidence": "evidence/import/results.txt",
      "kind": "旧问题仍存（当前源码重新核实）",
      "counter_evidence": "无真实DB/MQ/外部调用；除明确标为本轮javac的项目，均为当前源码链路核对，不复用旧实跑作为当前实跑。",
      "previous_id": "02",
      "reviewer_id": "IP02"
    },
    {
      "id": "03",
      "p": 2,
      "title": "导入显式非法limit仍退化为全量真写",
      "scope": "05 / 07 / 08 import-publish",
      "file": "application/src/main/java/cn/jojo/cc/biz/service/english/dict/EnglishDictImportBizServiceImpl.java",
      "start": 353,
      "end": 355,
      "trigger": "english.import.enabled已开，JSON显式limit=0或-1，省略dryRun。",
      "mechanism": "Param.parse直接getInteger，无正数校验；execute只在limit>0截断，dryRun默认false。显式无效小批参数变成整文件执行。",
      "impact": "整文件调用百度并建待发布词条，音频由后续回填Job统一处理；显式无效小批参数扩大到全量写入。",
      "fix": "显式提供limit时在下载前拒绝<=0以及越界/非整数字段；只允许省略表达全量。",
      "validation": "本轮原完整Reader/Normalizer与原Param javac隔离执行，见 evidence/import/results.txt",
      "evidence": "evidence/import/results.txt",
      "kind": "旧问题仍存（当前源码重新核实）",
      "counter_evidence": "无真实DB/MQ/外部调用；除明确标为本轮javac的项目，均为当前源码链路核对，不复用旧实跑作为当前实跑。",
      "previous_id": "03",
      "reviewer_id": "IP03"
    },
    {
      "id": "06",
      "p": 2,
      "title": "缓存失效异常被吞成发布成功，下一次批量也不再扫描该词",
      "scope": "05 / 07 / 08 import-publish",
      "file": "application/src/main/java/cn/jojo/cc/biz/service/english/dict/EnglishPublishBizServiceImpl.java",
      "start": 257,
      "end": 259,
      "trigger": "PROD提交且JY已标PUBLISHED后，clearRedisCommonCache同步抛错；例如有界队列拒绝后fallback MQ发送失败。",
      "mechanism": "PROD写成后先把JY status置PUBLISHED；缓存失效异常仅catch日志，无补偿身份。批量按status=UNPUBLISHED扫描，因此下轮不再拿到该行。clearRedisCommonCache内部异步丢投也不一定抛回。",
      "impact": "PROD已新而缓存仍旧，直到实际TTL/手工重发/另一次有效失效；批量报告成功无法证明学生已看到新内容。",
      "fix": "隔离后续失效动作，失败返回诚实的部分成功/重试身份，并保证可重放；不能声称重跑pending会自动覆盖status1。",
      "validation": "当前源码静态核验",
      "evidence": "import-analysis.md",
      "kind": "旧问题仍存（当前源码重新核实）",
      "counter_evidence": "无真实DB/MQ/外部调用；除明确标为本轮javac的项目，均为当前源码链路核对，不复用旧实跑作为当前实跑。",
      "previous_id": "06",
      "reviewer_id": "IP05"
    },
    {
      "id": "10",
      "p": 2,
      "title": "补录重复消费和重试仍先查百度，再幂等复用已有词",
      "scope": "05 / 07 / 08 import-publish",
      "file": "application/src/main/java/cn/jojo/cc/biz/service/english/dict/SegmentAutoFillBizServiceImpl.java",
      "start": 142,
      "end": 144,
      "trigger": "同词多题的延迟MQ或消费重放；库中已经有已发布词、人工草稿、导入草稿或已删词。",
      "mechanism": "autoFillOne首步queryBaiduSafely，随后文本锁内saveWordForAutoFill才查已有（含删除行）。TTS已移到异步回填，不再逐次生成或上传。",
      "impact": "重复投递、发布失败重试、已有人工草稿或删除词都仍消耗百度配额；不会重复建词；本轮不再声称重复TTS/OSS。",
      "fix": "先按词条状态判补录阶段并锁内重检；旧补录待发布只重试发布，不重新做外部生成。",
      "validation": "当前源码静态核验",
      "evidence": "import-analysis.md",
      "kind": "旧问题仍存（当前源码重新核实）",
      "counter_evidence": "无真实DB/MQ/外部调用；除明确标为本轮javac的项目，均为当前源码链路核对，不复用旧实跑作为当前实跑。",
      "previous_id": "10",
      "reviewer_id": "IP06"
    },
    {
      "id": "13",
      "p": 2,
      "title": "复合词性验证归一化但落库仍写超长原串",
      "scope": "词典维护/发布/补录/批量任务/缓存",
      "kind": "旧问题仍存（当前源码重新核实）",
      "file": "application/src/main/java/cn/jojo/cc/biz/service/english/dict/EnglishDictWriteTxService.java",
      "start": 531,
      "end": 533,
      "trigger": "HTTP pos传重复有效词性组成122字符原串",
      "mechanism": "NotBlank无Size；isSupportedPos临时归一化n.并接受；buildTranslationWrites仍存item.getPos，超过VARCHAR96。",
      "impact": "严格MySQL模式DataTooLong导致整个词条保存失败；宽松模式可能截断。",
      "fix": "见相应专项报告中的修复边界与拷打问题。",
      "validation": "当前源码静态核验",
      "evidence": "import-analysis.md",
      "previous_id": "13",
      "reviewer_id": "EXISTING-POS",
      "extraEvidence": [],
      "counter_evidence": "无真实DB/MQ/外部调用；除明确标为本轮javac的项目，均为当前源码链路核对，不复用旧实跑作为当前实跑。"
    },
    {
      "id": "14",
      "p": 2,
      "title": "管理搜索未按保存规则压缩连续空白",
      "scope": "05 后台单词/短语精确搜索",
      "kind": "旧问题仍存（当前源码重新核实）",
      "file": "application/src/main/java/cn/jojo/cc/biz/service/english/dict/EnglishPhraseBizServiceImpl.java",
      "start": 129,
      "end": 131,
      "trigger": "已存take off，搜索take  off",
      "mechanism": "保存归一化单空格，搜索只trim，再按normalized列eq。",
      "impact": "允许的归一化精确搜索无法命中。大小写是否出错取决于DB collation，不用其做确定反例。",
      "fix": "见相应专项报告中的修复边界与拷打问题。",
      "validation": "当前源码静态核验",
      "evidence": "import-analysis.md",
      "reviewer_id": "EXISTING-SEARCH",
      "counter_evidence": "无真实DB/MQ/外部调用；除明确标为本轮javac的项目，均为当前源码链路核对，不复用旧实跑作为当前实跑。",
      "previous_id": "14"
    },
    {
      "id": "23",
      "p": 2,
      "title": "新批量发布Job接受limit=0和空参数段，意外发布全部待发布词",
      "scope": "05 / 07 / 08 import-publish",
      "file": "api/admin-worker/src/main/java/cn/jojo/cc/worker/task/EnglishBatchPublishTask.java",
      "start": 148,
      "end": 150,
      "trigger": "控制台显式填limit=0（或纯0）；或误填只含逗号的非空参数。",
      "mechanism": "isNumeric接受0，parse返回limit0，nextBatchSize把<=0解释为无限；只含逗号的raw.split结果无有效键，也返回type=all/limit0。本类注释明确配错抛错，但未区分“省略limit”与“显式0”。",
      "impact": "试跑配置错误会直接跨库发布所有待发布内容，可能把未完成审核的人工草稿送至学生端；没有dryRun与任务撤回可兜。",
      "fix": "只有空参数或省略limit表达全量；显式limit校验>0；非空参数必须至少解析一个有效键值，不接受分隔符空集。",
      "validation": "本轮完整原Task javac，内存发布服务替身，显式0/逗号全量，150/2正常限量；见 evidence/import/results-batch.txt",
      "evidence": "evidence/import/results-batch.txt",
      "kind": "旧问题仍存（当前源码重新核实）",
      "counter_evidence": "无真实DB/MQ/外部调用；除明确标为本轮javac的项目，均为当前源码链路核对，不复用旧实跑作为当前实跑。",
      "reviewer_id": "IP08",
      "previous_id": "23"
    }
  ],
  "old_status": [
    {
      "previous_id": "04",
      "status": "已修复",
      "evidence": "EnglishDictWriteTxService.savePhraseForImport显式IMPORT，避免异步回填按source误跳过。"
    },
    {
      "previous_id": "11",
      "status": "已修复",
      "evidence": "autoFillOne先完成callWithWordLock，再publishWord；不再持文本锁进入ID锁。"
    },
    {
      "previous_id": "07",
      "status": "改设计后保留风险，不计当前违约代码缺陷",
      "evidence": "Spec9.4/12.3/17.2承认丢投无自动兜底；Plan08 Goal/提交后可恢复投递仍矛盾。"
    },
    {
      "previous_id": "08",
      "status": "随unmatched删除失去原触发条件",
      "evidence": "无待清理unmatched表，旧先删segment后删unmatched失败机制不存在；分词孤儿清理另由分词专项审核。"
    }
  ],
  "new_observations": [
    {
      "title": "格式非法行没有进入失败计数",
      "evidence": "ImportBiz.importPhrases L86-89;execute L128-149;reportInvalid L279-287",
      "mechanism": "execute只收到合法rows；非法项、文件内重复仅事后warn，回执三计数不含它们；全非法文件可回新建0/跳过0/失败0。",
      "classification": "统计边界/材料需明确；Spec10.1允非法行独立日志，不直接定为新增代码缺陷。"
    }
  ]
}