Files
Jyotisha/docs/tasks/TASK-report-chapter-export-fix-20260924.md
T

66 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TASK · 报告导出 CRLF 围栏合同冲突(2026-09-24)
## 状态 / 基线
**待领取。产品 2026-09-24 已批准 D5 有限例外(见决策记录 D14),本文件即执行授权。**
基线更新:`origin/staging` 含已部署的 `1420471a`(两单组合已合入),从该基线开分支 `codex/report-chapter-export-fix-20260924`。
基线 `5ff43b47f38e378918c8b6bd967228185d7f02fe`,发现于尚未提交的 `codex/report-chapter-export-20260924`,组合候选 `codex/chart-report-integration-20260924`。原报告单完成本地实现后,独立审查发现本项;继承旧剥离器缺陷,不是新增回归。后续必须在两单组合版本之后串行执行,不覆盖在途工作。
## 事故实证
- `frontend/src/lib/report-chart-block.ts` 的 `FENCE_RE`(当前83行)在语言标记后仅允许LF;`stripReportChartBlocks`(当前202–204行)直接使用该正则。
- 新 `report-export-blocks.ts` 的正文块与旧 `ordinaryReportDownloadMarkdown()` 都调用旧剥离器。
- 只将真实引擎虚构fixture `frontend/tests/fixtures/report-density-fictional-reader.json` 的markdown从LF转为CRLF,构造正文块并join:正文25块,下载中残留22个 `jyotish-chart` JSON围栏;仍与旧导出逐字节相等。分盘另能正确提取22个出现项。
- 相关105条测试通过未覆盖“含真实图盘围栏的CRLF输入无JSON”;已有CRLF字节等价测试不足以证明禁止JSON合同。
复现核心(在既有Node22/tsx环境运行,仅读虚构fixture,不写资料):
```ts
const markdown = fixture.markdown.replace(/\n/g, "\r\n");
const body = buildReportExportBlocks({ markdown }).filter(b => b.group === "body");
const output = joinExportBlocks(body);
console.log({
residualJsonFences: (output.match(/```jyotish-chart/g) ?? []).length,
equalsOldExport: output === ordinaryReportDownloadMarkdown(markdown),
});
// 实测:{ residualJsonFences: 22, equalsOldExport: true }
```
## 根因与旧防线
语言标记后 `\n` 不匹配 `\r\n`;投影允许供阅读组件消费的图盘结构,普通导出还需剥除围栏。BUG-999/1003投影及安全SVG防线不应撤销,当前缺的是下载剥离器换行边界;不能把ordinaryOutputLeaks为空替代无JSON独立断言。
## 决策记录
- 原单D5明确不可让步:正文全选与**旧版本**普通导出逐字节相同。
- 原单T1同时禁止JSON图盘围栏,CRLF输入下这两条无法同时成立。
- 用户后续D13只允许并要求SVG,不授权保留JSON,也未授权改变D5。
- **D14(产品 2026-09-24 批准)**:D5 对 CRLF / 混合换行输入中的 `jyotish-chart` JSON 围栏残留作有限例外——新导出必须删除这些围栏,因此 CRLF 输入下与旧导出不再逐字节相同;差异**只能**是被删掉的围栏(及其紧邻的围栏换行)。LF 输入仍须与冻结的旧导出逐字节相同,其它正文、安全 SVG、顺序一律不变。
- 仍禁止只比较两个共同修改后的 helper 来声称历史行为等价(见任务分解第 1、4 条的冻结 golden)。
## 硬红线
不标准化整篇换行,不改SVG几何/投影allowlist,不改生成/API/数据库,不新请求,不动依赖或workflow。保留单一大纲、既有下载器、全部测试名称与三栏断言记录。
## 任务分解(获准后)
1. 冻结基线LF golden旧导出结果及hash;另记录CRLF旧输出与22围栏事实。
2. 最小修改语言标记后的换行匹配为 `\r?\n`,检查边缘空白处理而非全篇replace。
3. 新增真实golden转换CRLF/混合换行测试:所有正文无JSON围栏;原安全SVG、其它文本字节与顺序保持;ordinaryOutputLeaks为空;分盘出现数不变。
4. LF golden必须与冻结旧版本结果逐字节相等。CRLF差异必须仅为获准移除的围栏,不得仅比较两个共用修改后helper的函数。
5. 跑tsc/lint/全量名称多重集合与失败诊断对照、实际下载;更新D5有限例外、PROGRESS、BUG-1020、BLOCKED、testing。构建/真机缺口如实保留。
## 让步顺序
不让步安全投影或JSON禁止,不静默改D5;无授权则保持blocked。构建环境缺口可留清单,不能写成通过。
## 开工前置命令
先 `git status -sb`,再 `git fetch origin --prune`,核对两单实际交付基线;获准后创建独立worktree,不在脏树切分支/reset/stash。重读AGENTS/frontend约束及本次BUG记录,Node22下跑报告定向基线。没有真实账号不得借凭据验收。
## BUG编号
组合候选核对最大号1019,本项暂记BUG-1020。正式领取时再次核对远端;若被占用顺延,不覆写其它会话记录。