Files
Jyotisha/docs/tasks/PROGRESS-consult-gender-optional-20260927.md
T
Jesse_ChenandClaude Opus 5.5 9aa37197a4
Independent Staging Quality Gate / validate (push) Successful in 12m53s
Independent Staging Quality Gate / publish (push) Successful in 3m27s
docs(tasks): gender optional acceptance
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-09-27 18:38:00 +08:00

89 lines
9.8 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.
# PROGRESS · 星盘资料加「性别(选填)」(2026-09-27)
任务书:`docs/tasks/TASK-consult-gender-optional-20260927.md`。执行:Claude 子代理(产品授权直接执行)。分支 `codex/consult-gender-optional-20260927`,工作树 `.worktrees/consult-gender-optional-20260927`。**未推送、未部署。**
## 基线
- 开工基线 `origin/staging` = `7a06aa00`(已含数据卡 v2 `5671039a` 与 BUG-1060)。之后 staging 只多了一条纯文档提交 `dd85d996`(BUG_HISTORY 三行),与本分支合并无冲突。
- 基线实测(Node 22.14,独立基线工作树):前端 4174 条 / 24 失败 / 28 跳过(24 条均为无 Docker 的 DB / 部署套件);Python 门禁集全绿(1 跳过);`next build --webpack` 后 `/`、`/chart`、`/ephemeris`、`/people` 均 ○ Static;首屏 rootMainFiles gzip(9) 660,412 字节。
## 提交
| 任务 | 提交 | 内容 |
| --- | --- | --- |
| T1 数据层 | `b912f63c` | 迁移 `20260927010000_profile_gender.sql`;账户 GET/PATCH、人物 POST/PUT/GET、主体解析、普通对话路由带上各自的性别;DB 测试 |
| BUG-1062 | `3abae68f` | 迁移 `20260927020000_profile_adopted_birth_service_role_select.sql` + 静态合同;BUG-1062 / BUG-1063 记录 |
| T3 婚恋卡 | `228ada22` | 数据卡婚恋段 `gender` = 当前人物的值;精简清单按有无切换;方法论缓存按性别分键 |
| T2 界面 | `53c657a8` | 人物编辑表单与「设置 → 个人资料」的选填单选;详情显示;DESIGN / VOICE;截图 |
| T4 记录 | 本提交 | CHANGELOG、本文件、真机清单、任务索引、BLOCKED |
## T1 数据层
- 取值:存 `female` / `male`,不填 = `null`(界面显示女 / 男 / 不填;与 `ayanamsa` 一样用英文键存)。
- 迁移只做加法:`profiles.gender`、`chart_profiles.gender` 两列可空、无默认、无回填;CHECK 只约束新列(`gender is null or gender in ('female','male')`);列授权照邻近出生列:`profiles` 给 authenticated `UPDATE`、service_role `SELECT/INSERT/UPDATE`(账户 PATCH 走服务角色,BUG-600 教训),`chart_profiles` 给 authenticated `INSERT/UPDATE`;两表 SELECT 本来就是表级授权 + 仅本人 RLS。admin_runtime 不授权(与 birth_date 同级)。
- 为什么对已部署代码向后兼容:旧代码从不 select / 写 `gender`,旧的人物插入列集照样成功、新列留空;回滚应用后列闲置。
- 读写位置:
- 本人:`PATCH /api/account` 接受 `gender`(zod `enum(female, male).nullable().optional()`,strict schema 其他值 400);`GET /api/account` 返回;普通对话路由 `loadProfile` 选列加 `gender`。
- 他人:`parseChartSubjectWrite` 只有请求里**带了** `gender` 键才写这一列(不认识这个字段的调用方不会把它清掉),`null` / `""` 清空,非法值 400;jsonb 回滚镜像不放性别;`libraryProfileFromSubjectRow`、`CHART_SUBJECT_SELECT` / `CHART_SUBJECT_API_SELECT` 带上。
- 主体解析:`chartProfileToConsultationRow`、`resolveSubjectBirth`(他人 accountRow)带各自的值;`ServerChartConsultation.gender` 取当前主体,不进 `toolInput`(引擎收不到)。
- 前端 `Profile.gender?`、`readProfile` 只在有值时带出。
- `ACCOUNT_BIRTH_SELECT` 未加 `gender`(报告、星盘、星历等不需要,缩小影响面)。
## BUG-1062(开工时顺带查出,在本单关键路径上)
- 本人性别走 `PATCH /api/account`,这条路由用服务角色读 `profiles`。用迁移全集静态比对:PATCH 与 `ACCOUNT_BIRTH_SELECT` 读取的列里,`active_birth_date / active_birth_timezone_offset / active_birth_provenance`(`20260920020000` 加的)没有任何 service_role `SELECT` 授权,按 BUG-600 的机理会 42501 → 500。本机无 Docker,未在真实库复现,状态写 investigating。
- 修复:补 SELECT 授权(只读、幂等);新增静态合同 `profile-service-role-grants-20260927.test.ts`(去掉新迁移时红、加回后绿)。`database-profile-gender.test.ts` 第二条在真实 PostgreSQL 上走 PATCH,门禁 DB job 会顺带证实。**这是任务书外的改动,单独一个提交,验收方可按需拆出。**
- BUG-1063:他人报告 worker 用服务角色读 `chart_profiles`,但服务角色对这张表没有任何权限(`20260718100000` revoke all 后没授回)。授权范围需要决定,本轮只记录。
## T3 婚恋卡
- `buildEvidenceCard(sources, { gender })`:婚恋段 `gender` = 「女」/「男」,没填 = 「性别未知」(规格位 `genderUnknown` 改名 `gender`,只有婚恋段有)。标签仍是卡片唯一自写字符串(`EVIDENCE_CARD_LABELS` 加 `genderFemale` / `genderMale`)。
- 精简清单:`condensedConsultationChecklist(domain, { gender })` 只替换那一行。填了时按 `strict-workflow-router.md` §4「先确认性别与昼夜盘」与仓内 `references/oracle/gender_interpretation_contract_2026_07_19.json`:女 = 夫星以木星为主、部分传承兼看火星;男 = 妻星取金星;都只作补充,核心仍是 7 宫、7 宫主、D9、UL、DK,不得只因配偶星的大运 / 过运定婚期。行数不变(7 行)。
- `consultationMethodologyForDomains(domains, { gender })` 的缓存键加上性别——否则第一位用户的清单会被缓存后发给下一位(测试覆盖了这条)。
- 系统提示里旧句「If gender … is present in future profile context」改为指向数据卡的 gender 字段(`src/mastra/index.ts` 一行,内容规则不变)。
- 遥测只记字段 id,测试确认性别值不进遥测、不算引用字段。
- 测试(真实 `getJyotishAgent` + 记录提示词的假模型,golden 引擎数据):填女 / 男 → 卡上有性别、清单无「性别未知」;不填 / null → 相反;同一进程依次跑 本人(女) → 他人(未填) → 他人(男) → 本人(女),每轮取当轮人物的值(经 `prepareConsultationRoute` 真实解析,本人是女时他人未填仍是「性别未知」)。
## T2 界面
- 一个组件 `ProfileGenderField`(女 / 男 / 不填,44px,一行说明),两处用:
- 星盘档案编辑表单(出生地点之后、岁差之前),随「保存」提交,「不填」写显式 `null` 以便清空。
- 「设置 → 个人资料」(本人唯一入口):选中即单独 PATCH `{gender}`,显示「已保存。」,保存中禁用、无 spinner。出生资料保存(`persistProfile`,含开场)不带性别,不会误清。
- 详情卡加「性别」行(没填「未填」);本人下面一行灰字「在「设置 → 个人资料」里改」,本页不给本人第二个入口(产品偏好:少入口)。
- 开场 / 注册不问(测试锁住 `home-onboarding-shell.tsx` 不含性别)。
- `page.tsx`:只多解构一个 `persistGender` 并传给 `ProfilePanel`(+1 行,useState / useRef 数不变)。
- 截图(本地 `next build --webpack` + `next start` + Chrome 无头,临时 harness 页渲染真实组件与虚构人物,harness 未提交):`docs/testing/consult-gender-optional-20260927/` 下 390 与 1280 各 4 张(他人详情、本人详情、编辑表单、个人资料选中「女」后)。CDP 检查:无横向溢出,性别按钮全部 ≥44px,点「不填」后草稿跟着变,个人资料点选后出现「已保存。」。
## 既有断言变更
无。既有测试文件只改了 `tests/consult-natal-agent-test-support.ts`:`runNatalAgent` 加可选 `serverChart` 参数(默认值不变),没有改任何断言。
## 验收数据(交付 HEAD,Node 22.14)
| 项 | 基线 `7a06aa00` | 交付 |
| --- | --- | --- |
| `tsc --noEmit` | — | 0 错 |
| `npm run lint` | — | 0 error |
| 前端全量 | 4174 / 24 fail / 28 skip | 4192 / 24 fail / 30 skip |
| 失败名单 | 24 条 DB/部署 | 与基线逐条一致;消失的测试名 0;新增 18 条(2 条 DB 在本机 skip) |
| Python 门禁集(含 growth contract) | 全绿,1 skip | 全绿,1 skip |
| `next build --webpack` | `/` `/chart` `/ephemeris` `/people` ○ Static | 同 |
| 首屏 rootMainFiles gzip(9) | 660,412 B | 661,444 B(+0.16%) |
## 环境缺口
- 无 Docker:`npm run test:db` 未跑。新增 `frontend/tests/database-profile-gender.test.ts`(列形状、CHECK、RLS 本人可读写 / 他人不可见不可改、旧插入列集照样成功、service_role 写、admin_runtime 无权;真实路由 POST/PUT/GET 人物与 PATCH 账户、陌生人 404 / 列表为空),本机两条 skip,**结果以门禁 DB job 为准,run 号待推送后补记**,不得写成已通过。
- 无登录态与模型凭据:婚恋回答是否真的按性别取夫星 / 妻星,按 `docs/testing/consult-gender-optional-20260927.md` 部署后真机走。
- Skill 文本未改(SKILL.md 基础段描述加 D9 摘要 / 性别字段一项不是必须,本轮不做,不 bump)。
## 未做 / 留给验收方
- 推送、部署、门禁 run 号。
- BUG-1063 的修法决定。
## 验收(Claude,2026-09-27)
rebase 到 `dd85d996` 后独立复跑(Node 22.14,顺序执行):tsc 0;lint 0 error;`npm test` 4192 / 24 fail / 0 cancelled / 30 skip,失败名单与 BUG-1060 分支基线逐条一致、无消失测试名(新增 2 条 DB 测试本机跳过);Python 门禁集退出 0;`/`、`/chart`、`/ephemeris`、`/people` ○ Static;rootMainFiles gzip(level 9)130933 B。迁移只加可空列 + CHECK + 列级授权,对已部署代码向后兼容;BUG-1062 补丁只加 service_role 列级 SELECT(我核对了 `20260920020000` 确实未授予)。截图核对:编辑表单「性别(选填)」三选一 + 一句说明。
待门禁:`database-profile-gender.test.ts` 与 `profile-service-role-grants` 的真实库结果以本次推送的门禁 DB job 为准(run 号补记)。BUG-1063(报告 worker 以 service_role 读 `chart_profiles` 无授权)待产品/安全决定。