Files
Jyotisha/docs/tasks/TASK-beta-main-path-20261014.md
T

106 lines
12 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 · 内测主路径:他人报告读不到资料、AI 生成标识与免责、状态板清账、内测冒烟清单(2026-10-14)
- 日期:2026-10-14
- 来源:产品 10-14 拍板「内测跑生产」「给别人出报告内测要开」;内测体检(`scratchpad/beta-compliance-20261014.md`、`beta-defects-20261014.md`)。
- 执行方:**Grok(Windows + Docker)**,分支 `codex/beta-main-path-20261014`,只推这个分支
- 验收:Claude(Linux)
- BUG 编号:开工时核对 `docs/BUG_HISTORY.md` 最大号顺延(写作时最大号 BUG-1317;#56 从 1318 起、#58 预留 1328,以实际为准)。T1 沿用 **BUG-1063**;T2 新号;T3–T5 不取新号(状态与文档)。
- 串行:与 #56(Python 引擎)、#57(校正打分)、#58(Node 资源)、容量单 `TASK-beta-capacity-20261014`(限流 / 排队)**不改同一文件**;T2 改 `frontend/src/components/chat-composer.tsx` 与报告阅读组件,若同期有别的单改这两个文件,以先合入者为准、后者变基。
## 1. 基线
- 基线 commit:`origin/staging` `48a2fadd`(开工时以最新为准,进度记录写明)。
## 2. 事故实证(行号按符号定位)
**T1 / BUG-1063 他人报告读不到资料**(状态 investigating,09-27 静态证据):
- `frontend/src/lib/personal-report-worker-subject.ts::loadReportWorkerProfile` → `frontend/src/lib/subject-birth.ts::loadSubjectBirth(client, …)`,用后台 admin 客户端 `from("chart_profiles").select(CHART_SUBJECT_SELECT)`。
- admin 客户端在自托管模式下是 `set local role service_role`(`admin-client-core.ts`)。
- `frontend/supabase/migrations/20260718100000_repair_missing_chart_profiles.sql` 第 50 行 `revoke all on table public.chart_profiles from anon, authenticated, service_role;`,之后**没有任何迁移**给 `service_role` 授回 `chart_profiles` 的任何权限(已 grep 全部迁移:只有给 `authenticated` 的 select / 列级 insert / update / delete)。
- 本人报告不受影响:本人出生资料在 `profiles` 表;只有「人物档案里的其他人」走 `chart_profiles`。
- 推断后果:他人报告 worker 读资料报权限错 → `subject_unavailable` → `profile_incomplete`(可重试)→ 一直排队或最终失败退款。**未在真实库复现。**
**T2 AI 生成标识**:只在协议文本里(`frontend/src/lib/legal-documents.ts`「本服务的回答与报告由人工智能生成……」);报告结尾有「不构成医疗、法律或投资建议」(`personal-report-generation.ts`);**对话界面(普通对话、校正对话)与报告阅读页顶部都没有显式标识,对话里也没有免责小字**。依据:《人工智能生成合成内容标识办法》2025-09-01 施行,要求对生成的文本内容在起始、末尾或中间适当位置添加显式提示(来源:国家网信办 https://www.cac.gov.cn/2025-03/14/c_1743654685899683.htm ;解读 https://www.pwccn.com/zh/tmt/method-identifying-synthetic-content-generated-ai-sep2025.pdf )。
**T3 / BUG-1080 新账号首次建盘只见兑换弹窗**:修复 `dec36bce` 已在 staging(已核:`git merge-base --is-ancestor dec36bce origin/staging` 成立),状态行仍写「修复在分支,未部署」。只差真机。
**T4 / BUG-283 今日星语回退**:状态 regressed,但修复版本写「已被 BUG-299 覆盖」,BUG-299 为 resolved(首屏只调 `/api/daily_guidance`)。实为状态未改。
**T5 状态板滞后**(修复已在 staging,状态行仍写「分支 / 未部署」):
| BUG | 状态行现写 | 事实 |
| --- | --- | --- |
| 906、907 | investigating(分支已修,未部署) | `82c8aeb0` 在 staging |
| 1080 | investigating(分支,未部署) | `dec36bce` 在 staging |
| 1128 | 字体部分 resolved(待部署)/ JS 部分 blocked | `8112f62b` 在 staging;JS 部分 blocked 保持 |
| 1244、1245、1247~1253、1255~1259 | fixed-pending-verify(分支 `codex/…`;部署前不标) | 均已部署 staging(见各自修复版本行或 CHANGELOG);1246 已撤回,不动 |
| 1254 | fixed-pending-verify(需门禁连续通过) | 按门禁记录核实 |
## 3. 根因
- T1:7-18 修 `chart_profiles` 权限时按「只给登录用户」收口,没考虑后台 worker;9-27 BUG-1031 把 worker 改走 `loadSubjectBirth` 后才用到这张表;mock 客户端测不出表权限。
- T2:合规那一轮(09-30)只做了协议与同意,没有落到界面。
- T3–T5:多会话并行合入时只改代码不回填状态行。
## 4. 决策记录(产品 2026-10-14)
1. 内测开放「给别人出报告」→ BUG-1063 必修。
2. **T1 修法选「给 `service_role` 授 `chart_profiles` 逐列只读」**,不选 SECURITY DEFINER 只读函数。理由:① 调用方是只在服务端运行的后台 worker,`service_role` 本来就读得到本人出生资料(`profiles`),把同一组列扩到他人档案不扩大信任边界;② 定义者函数对受信的服务端调用方不提供额外保护(它照样能传任何 user_id),却多一条读路径要维护、要和 `CHART_SUBJECT_SELECT` 同步两处;③ 列级授权能精确限制到 `CHART_SUBJECT_SELECT` 的列,用一条合同测试锁住「select 列 ⊆ 授权列」。只授 SELECT,不授写。
3. **T2 显式标识放法**:对话——在 `ChatComposer` 组件内输入框下方加一行小字(一个组件,普通对话与校正对话两处同时生效,`page.tsx` 不改);报告——阅读页标题下的元信息行加「AI 生成」,结尾免责保留;分享出去的报告页同样有。**推翻 `frontend/DESIGN.md`「No strip below the composer」的字面**:那条针对的是常驻 44 px 空条;本单是一行说明文字、不占工具位,DESIGN 同步改写这条并写明原因。文案建议:对话「回答由 AI 生成,仅供参考,不构成医疗、法律或投资建议。」;报告「本报告由 AI 生成,仅供参考。」(对照 VOICE,产品可改字)。
4. 隐式标识(文件元数据):下载的 PDF / Word / Markdown 写入「AI 生成」元数据——列为 T2b,可让。
5. T4:BUG-283 改为 `superseded`(被 BUG-299 取代),不改代码;首页今日星语是否正常放进冒烟清单,真机若仍失败另立新号。
6. T5 只按事实改状态行(「已部署 staging `<sha>`,真机欠」),**不得**把 fixed-pending-verify 改成 resolved,不改根因与结论。
## 5. 硬红线
1. 迁移只做加法(`grant select (<列>) on public.chart_profiles to service_role`),对当前已部署代码向后兼容;新迁移文件名时间戳不得与现有重复;动表的轮次**必须真跑 `npm run test:db`**(AGENTS §7.6),Grok 有 Docker。
2. 不授 `service_role` 任何写权限;不改 RLS;不动 `authenticated` 现有授权。
3. 前端红线(AGENTS §7):tsc 0、lint 0 error、npm test 失败名单与基线逐名相同(看 `# cancelled` 与退出码)、build `/` Static、首屏 gzip ±2%;`page.tsx` 的 `Home()` 状态数不增长;改 UI 同提交更新 DESIGN;新文案进 VOICE。改既有断言写「原值 / 新值 / 原因」三栏(先 grep `frontend/tests/` 里按 `chat-composer` 源码文本断言的合同测试,AGENTS §7.8)。
4. 不改生时校正打分、不改对话提示词、不改报告生成内容(只加阅读页与组件上的标识)。
5. 不写真实用户资料;测试只用公开名人或虚构盘。不改 workflow、不推 staging。
## 6. 任务分解
| 项 | 内容 | 验收 |
| --- | --- | --- |
| T0 | **先红后绿**:在 `frontend/tests/database-chart-subject.test.ts`(或新建 `database-report-worker-subject.test.ts`)加用例:用后台 admin(`service_role`)客户端对另一个人物档案调用 `loadReportWorkerProfile` / `loadSubjectBirth`,期望读到资料。改前在本地 PostgreSQL(Docker `test:db`)跑出**权限拒绝**并把错误原文写进进度记录 | 进度记录有改前红的输出;若改前竟然是绿的(说明另有授权),停下回报,不做 T1 |
| T1 | 新迁移:`grant select (<CHART_SUBJECT_SELECT 的全部列>) on table public.chart_profiles to service_role;`。新增合同测试:解析 `CHART_SUBJECT_SELECT` 与迁移里的授权列,断言前者 ⊆ 后者(以后加列忘了授权会红)。BUG-1063 记录补根因确认、修复、验证 | T0 用例转绿;`npm run test:db` 全量与基线比对;合同测试;BUG-1063 → fixed-pending-verify(部署 + 真机给别人出一份报告后才 resolved) |
| T2 | 对话:`ChatComposer` 内输入框下方一行说明(`--type-overline`、`--color-ink-tertiary`,移动端不换行溢出,不挡发送键)。报告阅读页(`personal-report-page.tsx` / `personal-report-document-view.tsx` 标题区)与分享页加「本报告由 AI 生成,仅供参考。」。中英文两版(英文:「AI-generated. For reference only; not medical, legal or financial advice.」/「This report is AI-generated and for reference only.」) | 组件测试:两处对话面都渲染说明;报告中英文都有;移动端快照或断言 class;DESIGN、VOICE 更新;真机清单一条 |
| T2b | 下载文件写入「AI 生成」元数据(PDF Producer/Subject、DOCX core properties、Markdown 首行注释——按现有导出实现能力取舍) | 单元测试读回元数据;做不到的格式写进进度记录 |
| T3 | BUG-1080 状态行改为「修复 `dec36bce` 已部署 staging,真机欠」;冒烟清单收录 | 文档 |
| T4 | BUG-283 状态改 `superseded(由 BUG-299 取代)`;冒烟清单收录「首页今日星语」 | 文档 |
| T5 | 按 §2 表格逐条改状态行;每条写部署证据(提交号在 staging、对应部署记录或 CHANGELOG 行);1254 按门禁记录判断 | 文档;`tests/test_repo_privacy_markers.py` 过 |
| T6 | 冒烟清单:把 `scratchpad/beta-smoke-checklist-20261014.md` 草稿(由 Claude 随单附上)落成 `docs/testing/beta-smoke-20261014.md`,补上 T1/T2 的条目编号 | 文档 |
## 7. 让步顺序
T1 不可让(内测要开他人报告)。T2 对话与报告显式标识不可让(法规);T2b 可让。T3–T6 文档项不可让(产品需要一张真实的状态板),但不阻塞 T1/T2 的合入。
## 8. 验收门
- `npm run test:db`(Grok,Docker)全量,与 staging 基线比对;Claude 侧用本机 PostgreSQL 替身复跑 T0/T1 相关用例。
- 前端 tsc / lint / npm test / build / gzip。
- Python 不动;若碰到 `scripts/`,跑快速门全量。
## 9. 开工前置
```
git fetch origin --prune
git status -sb
git worktree add -b codex/beta-main-path-20261014 .worktrees/beta-main-path-20261014 origin/staging
grep -rn "chat-composer" frontend/tests | head # 找按源码文本断言的合同测试
```
## 10. 需产品提供 / 拍板
1. 同意 T1 修法(`service_role` 逐列只读)——若更倾向只读函数,告诉我,改单。
2. 标识文案:对话「回答由 AI 生成,仅供参考,不构成医疗、法律或投资建议。」、报告「本报告由 AI 生成,仅供参考。」——同意或改字;以及同意改 DESIGN「输入框下方不放东西」这条的字面。
3. 冒烟清单由谁走:产品用 staging 测试邮箱 + 固定验证码真机走,还是先由 Claude 用接口层(无浏览器)走一遍可接口化的条目(他人报告、「你好」不扣点、限流),再由产品补真机部分。
4. 生产首发后,冒烟清单是否在生产再走一遍(建议走前 5 条,用产品自己的账号)。
## 11. 产品答复(2026-10-14,覆盖上文对应建议值)
1. 标识文案**同意**:对话「回答由 AI 生成,仅供参考,不构成医疗、法律或投资建议。」;报告「本报告由 AI 生成,仅供参考。」
2. BUG-1063 修法按决策记录 2(逐列只读授权)。