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

11 KiB
Raw Blame History

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 条,用产品自己的账号)。