Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HwMNZEzdzmrbPhuRNmZe3C
12 KiB
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/staging48a2fadd(开工时以最新为准,进度记录写明)。
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)
- 内测开放「给别人出报告」→ BUG-1063 必修。
- T1 修法选「给
service_role授chart_profiles逐列只读」,不选 SECURITY DEFINER 只读函数。理由:① 调用方是只在服务端运行的后台 worker,service_role本来就读得到本人出生资料(profiles),把同一组列扩到他人档案不扩大信任边界;② 定义者函数对受信的服务端调用方不提供额外保护(它照样能传任何 user_id),却多一条读路径要维护、要和CHART_SUBJECT_SELECT同步两处;③ 列级授权能精确限制到CHART_SUBJECT_SELECT的列,用一条合同测试锁住「select 列 ⊆ 授权列」。只授 SELECT,不授写。 - T2 显式标识放法:对话——在
ChatComposer组件内输入框下方加一行小字(一个组件,普通对话与校正对话两处同时生效,page.tsx不改);报告——阅读页标题下的元信息行加「AI 生成」,结尾免责保留;分享出去的报告页同样有。推翻frontend/DESIGN.md「No strip below the composer」的字面:那条针对的是常驻 44 px 空条;本单是一行说明文字、不占工具位,DESIGN 同步改写这条并写明原因。文案建议:对话「回答由 AI 生成,仅供参考,不构成医疗、法律或投资建议。」;报告「本报告由 AI 生成,仅供参考。」(对照 VOICE,产品可改字)。 - 隐式标识(文件元数据):下载的 PDF / Word / Markdown 写入「AI 生成」元数据——列为 T2b,可让。
- T4:BUG-283 改为
superseded(被 BUG-299 取代),不改代码;首页今日星语是否正常放进冒烟清单,真机若仍失败另立新号。 - T5 只按事实改状态行(「已部署 staging
<sha>,真机欠」),不得把 fixed-pending-verify 改成 resolved,不改根因与结论。
5. 硬红线
- 迁移只做加法(
grant select (<列>) on public.chart_profiles to service_role),对当前已部署代码向后兼容;新迁移文件名时间戳不得与现有重复;动表的轮次必须真跑npm run test:db(AGENTS §7.6),Grok 有 Docker。 - 不授
service_role任何写权限;不改 RLS;不动authenticated现有授权。 - 前端红线(AGENTS §7):tsc 0、lint 0 error、npm test 失败名单与基线逐名相同(看
# cancelled与退出码)、build/Static、首屏 gzip ±2%;page.tsx的Home()状态数不增长;改 UI 同提交更新 DESIGN;新文案进 VOICE。改既有断言写「原值 / 新值 / 原因」三栏(先 grepfrontend/tests/里按chat-composer源码文本断言的合同测试,AGENTS §7.8)。 - 不改生时校正打分、不改对话提示词、不改报告生成内容(只加阅读页与组件上的标识)。
- 不写真实用户资料;测试只用公开名人或虚构盘。不改 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. 需产品提供 / 拍板
- 同意 T1 修法(
service_role逐列只读)——若更倾向只读函数,告诉我,改单。 - 标识文案:对话「回答由 AI 生成,仅供参考,不构成医疗、法律或投资建议。」、报告「本报告由 AI 生成,仅供参考。」——同意或改字;以及同意改 DESIGN「输入框下方不放东西」这条的字面。
- 冒烟清单由谁走:产品用 staging 测试邮箱 + 固定验证码真机走,还是先由 Claude 用接口层(无浏览器)走一遍可接口化的条目(他人报告、「你好」不扣点、限流),再由产品补真机部分。
- 生产首发后,冒烟清单是否在生产再走一遍(建议走前 5 条,用产品自己的账号)。
11. 产品答复(2026-10-14,覆盖上文对应建议值)
- 标识文案同意:对话「回答由 AI 生成,仅供参考,不构成医疗、法律或投资建议。」;报告「本报告由 AI 生成,仅供参考。」
- BUG-1063 修法按决策记录 2(逐列只读授权)。