交付出件箱

← 返回出件箱

🔴 云机会话交接件 · 2026-09-11(头图功能 + 三件待办)

新会话:从头到尾读完再说话。变傻的真因是「没查就说」——每条硬事实都附了自证命令,引用前先跑。
memory 和交接件只是参考,跟代码冲突以代码为准。
上一份:~/reports/CLOUD-SESSION-HANDOFF-20260908.md


第 0 节 · 防呆速查表(说错任何一条 = 事故)

事实 值 自证命令
工作 worktree /home/dev2/doctor-ai-brain/.claude/worktrees/bridge-cse_01EMELwQxxcDC31Mi2fSU2fL git -C <路径> branch --show-current
分支 feature/h5-hero-image 同上
未提交改动 0(已提交 b59a3905) git status --short
🔴 test 上待发生产的 MR #665 #666 #667 #668(四个) 见第 2 节
🔴 已上生产 MR #661(Phase78 机构管理手机端) · #664(平板 logo 白底) git log origin/main --merges -5
test 管理员 ljg_admin / Admin@1234 —
生产门店端席位 0007202609 / 338317(org 24) —
🔴 test 测试机构 id=24,真名「切换版验收测试有限公司」
⚠️ 本会话前期一直误称「压轴大师体验机构」,那是生产的 org 24
sudo db-query test "SELECT id,name FROM organizations WHERE id=24"
生产演示数据 周思源(org 24 · 6 次完整检查记录 · owner_type=seat) sudo db-prod "SELECT count(*) FROM refractive_records WHERE patient_id='2e77b5c8-09c2-4337-8bc4-b02f800e5e42'"
发 test sudo release-to-test --yes "标题" —
发生产 sudo release-to-prod --mr N --auto-merge --yes --title "..." —

🔴 部署判据(改哪儿看哪条线,本会话栽过)

改了什么 判据
settlement/** sudo release-pipeline-status settle-test 出新 run 且 SUCCESS
app/ web/app/ alembic/ migrations/ sudo test-inspect deploy 新 commit 戳

deploy/auto-update.sh:19 SERVICES=(api web) · :110 校验和只扫 app/ web/app/ alembic/ migrations/,
全脚本 0 处 settlement(对照组 web 6 处)。结算是独立容器 + 独立流水线。


第 1 节 · 长官规矩(10 条红线 · 一字不差)

1 生产不许乱发,我不明说就别发;test 也要等我说
2 报告秒读不许动;改视光档案必须 scene 隔离
3 下结论前物理 grep 带对照组;0 命中不带对照组无效;报 0 命中必写查询范围
4 比对两端功能必须前端页面+后端 schema 同时看,只看一边必错
5 memory 和交接件只是参考,跟代码冲突代码赢
6 派 agent 只一层;写码 sonnet、检索 haiku;agent 回来自己跑 verify,agent 会虚报
7 我问"这是你认真思考后给我的吗"= 你有推断没验证,停下列前提先查再答,别硬撑
8 我说"没看懂"就立刻用大白话重说,不许再堆术语
9 一次只问我一个简单问题;回复短、表格、表情
10 方案图上的原型标注、开发说明、标注专用色,一律不许做进功能里

本会话新增/强化


第 2 节 · 🔴 test 上待发生产的四个 MR

MR 内容 验收状态
#665 平台手机端首页文案「接入机构」→「开通机构」 ✅ 产物验过(新词命中 1/旧词 0/对照组有效)
#666 PC 机构管理加「门店物料」入口(授权证书/横竖版海报 · 查看+下载) ✅ 真点验过:三份 PDF 真下载、sha256 互不相同、授权书内容主会话亲眼核过
#667 PC 操作列低频项收进「更多」下拉(修 #666 造成的按钮截断回退) ✅ 9 个宽度实测,临界宽度 1650→1536
#668 头图功能(机构可传 4:1 头图整块替换家长端顶部品牌区) ✅ 零 mock 真登验过六条,详见第 3 节

发生产命令(四个一起):

cd <worktree>
sudo release-to-prod --mr 665 --mr 666 --mr 667 --mr 668 \
  --branch release/mr-665-668-20260911 --auto-merge --yes \
  --title "release: 开通机构文案 + 门店物料 + 更多下拉 + 头图功能"

⚠️ 长官未下令发生产,别自作主张。


第 3 节 · 头图功能(MR #668)已完成的全貌

需求(长官几轮收敛后的定稿)

机构可传一张 4:1 头图,整块替换家长端 /h5/chat 顶部绿底品牌区(Logo+机构名+介绍全由图承载);
没传图完全保持现状;☰ 菜单按钮保留浮在图上。本次只做手机端,平板不动。
上传主体 = 平台管理员代传(品牌方角色未立项,长官原话"我们代传,不用客户传")。

规格

项 值
尺寸 严格 1600×400,不符拒绝 + 回人话「当前为 {w}×{h},请重新导出」
大小/格式 ≤2MB · JPG/PNG/WebP · 服务端转 WebP
存储 key store_brand/{org_id}/hero-image-{时间戳}.webp(带时间戳防缓存旧图)
入口 PC 机构管理「更多」菜单首位 + 分隔线

🔴 严格限尺寸是长官"不用搞这么复杂"砍出来的简化,顺带消掉四个坑:
降采样只管 JPEG / 调用顺序错会静默失效 / 裁切要按新尺寸算 / 手机照片 EXIF 旋转。

改动五处(commit b59a3905)

  1. migrations/versions/org_hero_image.py(新增)加 organizations.hero_image_oss_key
    🔴 只 add_column 零 DROP · down_revision 挂 batch5_ai_conclusion(不是队尾的 34ec94466f0c)
    —— 物理核过 origin/main:前者在、后者不在。挂 main 上不存在的祖先,发生产 cherry-pick 会 KeyError 炸
  2. app/api/admin_orgs_access_link.py 三个 admin 端点 GET/POST/DELETE /api/admin/orgs/{id}/hero-image
  3. app/api/h5_store_card.py /home-branding 加 hero_image_url
    🔴 签名 URL 按整点对齐 expires = 3600 - now%3600 + 3600 → 同小时内 URL 一致,浏览器可缓存
  4. web/app/h5/chat/components/store-brand-hero.tsx 三态渲染(loading / 有图 / 无图)
  5. web/app/(dashboard)/admin/orgs/page.tsx 「更多」菜单 + 上传弹框

长官点名"要彻底解决"的四条,都已实现并验过

# 问题 治法 真机实测
闪 数据未到时先闪眼睛图标再变真 Logo(存量毛病,顺带修了) loading 态只渲染纯绿底空 div 源码实读:自闭合空 div 零子元素
跳 图到位把下方内容顶下去 minHeight 88 + transition .2s 骑缝标签 top 上传前 78px / 上传后 78px,逐像素相同
开天窗 图加载失败一片空白 onError 回落完整现状渲染 真机 OSS 不可达触发,确认回落完整绿底
重下 150KB 签名 URL 每次不同 按整点对齐 三次调用返回 URL 逐字节完全一致

🔴 唯一没能亲眼看到的:图在屏幕上显示

云机出网白名单不放行 OSS 域名(tongban-test-bj.oss-cn-beijing.aliyuncs.com
直连和走代理都返 000,对照组 test 站返 301 证明代理本身通)。

但用对照组证明了不是功能问题:现有机构 Logo 走完全同一条链路(同 OSS、同签名方法、同组件),
真机实测两者失败完全同因同错(ERR_TUNNEL_CONNECTION_FAILED,连接层被拒,
不是"到了 OSS 但鉴权失败"的 403)。而 Logo 在生产上已用很久 ⇒ 头图在真手机上也会正常。

补洞方式(二选一,长官未选):① 长官手机上看一眼 ② 请 root 把 OSS 域名加进白名单(一次性,以后所有图片验证都受益)

零 mock 真登方法(下个会话要复验时照抄)

  1. PC 后台给 org 24 批量生成 1 个席位 → 结果弹框给账号 + 临时密码明文
  2. 用该账号走真实 POST /api/seat/login → 首登强制改密 → 拿真 token
  3. 家长端 https://test.tongban.love/h5/chat?t=<PC后台取的访问链接>
    🔴 不许往 localStorage 塞假 token、不许 page.route 桩接口(长官点名批过一次)

第 4 节 · 🔴 下一个会话要做的三件(长官已拍板)

① Logo 加「移除」

现状:homepage_logo_oss_key 有上传、无删除(全仓零个删除/置空端点,已 grep 确认)。
传错了只能覆盖,回不到"没有 Logo"的状态。
→ 照抄头图的 DELETE 端点写一个。长官已同意。

② 头图加「显示开关」

长官原话:「加个显示开关吧,开了那个平板首页机构展示他就显示 logo,这个(头图)也开了就优先显示这个」
理解(主会话已向长官确认过这个理解,长官回"可以"):
- 头图需要一个独立的显示开关
- 「平板首页机构展示」开 → 显示 Logo
- 头图开关也开 → 优先显示头图(把 Logo 顶掉)
- 头图开关关 → 图还留着但不显示,退回 Logo
⚠️ 这意味着又要加一个字段 + 迁移。开关应该加在放 14 个功能开关的那张表
(先 grep 确认是 org_brain_config 还是别处,别猜)。

③ Logo 加载失败兜底(免裂图)

Logo 在 3 处渲染,全都没有 onError 兜底,加载失败就是浏览器原生裂图:
- web/app/h5/chat/components/store-brand-hero.tsx:200(手机端)
- web/app/h5/tablet/components/tablet-brand-hero.tsx:80(平板端)
- web/app/h5/settings/components/SeatStoreCard.tsx:328(门店设置页)
→ 失败退回眼睛图标(设计里本来就有这个 fallback,只是"传了但加载失败"没走到它)。
长官已同意。


第 5 节 · 挂账(不是这次的活,但是雷)

🔴 A. alembic 迁移链有两个未合并的头

34ec94466f0c        (8-29 · merge 4 heads)  ← main 上【没有】
batch5_ai_conclusion (9-02)                  ← main 上【有】

自证:git ls-tree -r origin/main --name-only -- migrations/versions | grep -c "batch5_ai_conclusion" → 1
   同命令换 34ec94466f0c → 0

危害:发生产是 cherry-pick 挑着搬,链分叉后容易挂到"main 上不存在的祖先"上 → KeyError 炸
(store_poster_demo_flag.py 里记着同款事故)。本次头图迁移特意避开了,但雷还在。
长官已知悉,同意「单独开一单处理,不跟业务功能混着发」。

🔴 B. test 机构 24 上留了一张测试 Logo,清不掉

做 Logo 对照组时传的。因为 Logo 没有移除功能(就是待办①),
而 sudo db-query test 只读(拒绝 UPDATE)⇒ 需要 root 用有写权限的工具清空
organizations.homepage_logo_oss_key(test 库,非生产,不紧急)。
⚠️ 待办① 做完之后,就能自己清了。

⚠️ C. test 机构 24 多出 3 个不明席位

0106202609 / 0024202607 / 0025202607,不是本会话创建的。
可能有别的会话在同时操作机构 24。动这个机构前先确认没人在用。

📌 D. 品牌方合作方案(未立项)

全文 ~/reports/brand-partner-plan-draft-20260909.md + memory project-brand-partner-plan。
已定:门店和品牌都是机构故只有「机构码」;卡片只能印品牌方的码;品牌码=拉新扣名额、
门店码=认领不扣名额;一个孩子只绑一个门店;关联挂在档案级不是席位级;
需新增 service_org_id 字段区分「谁带进来的」和「谁在服务他」。
🔴 还没定的 2 个小口子见 memory。长官原话「后边肯定还是要做品牌方这个事的,我还没跟你聊呢」。


第 6 节 · 🔴 本会话踩的坑(这节最值钱,务必读)

坑 1 · 单一分辨率下结论 —— 直接导致误判因果

加了「门店物料」按钮后,长官说"之前我都能看见"。我在 1440 宽量,得出
"生产本来就溢出 166px,我只是加剧",判成存量问题。
长官坚持后重测 10 个宽度:生产临界 1582px、test 1650px,差 68px = 新增按钮宽度,误差 0。
⇒ 真相是我把它弄坏的,回退区间 1582~1649px,长官屏幕正好在里面。
教训:宽度/尺寸类结论必须多点取样,单点必错。

坑 2 · grep 变量名验线上产物 —— 压缩会重命名

判断新版有没有上线,grep 线上 chunk 里的 saveError(被删的 state 名)返 0,
据此说"已上线,长官看到旧的是浏览器缓存"。错的 —— 打包压缩会把局部变量改名,
0 命中是必然。改查中文字符串常量立刻露馅(旧代码真的还在)。
memory:pitfall-verify-bundle-grep-string-not-identifier

坑 3 · 只抓第一个 chunk —— root 亲自纠正

验产物时 head -1 只取第一个 chunk,容易抓到 layout 文件,
那时阳性对照也会是 0,看起来像"功能没上",其实是查法失效。
必须遍历页面引用的全部 chunk。

坑 4 · 正则截断吞掉状态后缀

grep -oE "转发 [a-z]+/[a-z0-9-]+" 把后面的「失败/超时」切掉了,
于是把失败的转发看成了成功,报给长官"已同步"。
教训:截取型正则会丢掉关键后缀,判状态要看整行。

坑 5 · 拿错部署判据盯了 8 小时

改 settlement/ 却盯 test-inspect deploy(那条只管 doctor-web/api),
它报"部署成功"而实际 settle-test 流水线是 FAIL(类型错误),
代码根本没上线,干等 8 小时。同款误判 memory 8-13 记过一次,这是复犯。

坑 6 · esbuild 查不出"变量删了还有人用"

删了 9 个 state 后,esbuild 全绿 —— 但它只查语法不查变量存不存在,
删了变量还被引用照样编译通过,上线一点就白屏。
必须单独 grep 残留引用(本次查了,9 处命中全是注释,零真实引用)。

坑 7 · agent 会互相矛盾,必须自己看原文

两个 agent 对"既有字段是否被删"给出相反结论。
自己 grep 后确认:没删,只是 select 那行被重写(一减一加),复核 agent 误读 diff。
agent 冲突时别选一个信,自己看原文。

坑 8 · 我只看得到 agent 的最终回复

多次让 agent"贴原始输出",它只回"已贴完"/"完毕" —— 过程输出我根本看不到。
派单必须明写:「我只看得到你的最终回复正文,所有输出必须原样贴进最终回复,
只回『完成』= 任务失败」
,否则白跑。

坑 9 · 桥同步:mirror 有 ≠ Codeup 有

看到 mirror 上有新 commit 就去发版,工具拒了「还没同步到 Codeup」。
判据要用工具自己的,或确认 Codeup 侧。另外工具有时会误报
「跟 test 一致·无需发版」,那是 Codeup 还没拿到新提交,别信,继续等。

坑 10 · 出图:标注框被父元素 overflow:hidden 裁掉

效果图里橙虚线标注框挂在有 overflow:hidden 的内层元素上,渲染出来只剩一个碎片。
标注要挂在无裁切的外层。 —— 这是真渲染 + Read 看图才发现的,
纯看代码 100% 发现不了。出图交付前必须真渲染并用 Read 亲眼看。


第 7 节 · 验证命令(照抄可用)

W=/home/dev2/doctor-ai-brain/.claude/worktrees/bridge-cse_01EMELwQxxcDC31Mi2fSU2fL
cd $W && git status --short && git log --oneline -3

# 头图三个端点(应 get/post/delete)
export DATABASE_URL="postgresql+asyncpg://postgres:postgres@localhost:5432/doctor_ai_brain"
export JWT_SECRET_KEY="$(head -c 48 /dev/urandom | base64)"
python3 -c "from app.main import app; [print(p, sorted(m.keys())) for p,m in app.openapi()['paths'].items() if 'hero-image' in p]"
# 🔴 数路由必须用 app.openapi()['paths'],不许用 app.routes

# 迁移安全(零 DROP + 祖先在 main 上存在)
grep -ci "drop_column\|drop_table" migrations/versions/org_hero_image.py     # 期望 0
grep -c "add_column" migrations/versions/org_hero_image.py                    # 对照组 应 1
git ls-tree -r origin/main --name-only -- migrations/versions | grep -c "batch5_ai_conclusion"   # 应 1
git ls-tree -r origin/main --name-only -- migrations/versions | grep -c "34ec94466f0c"           # 应 0

# 桥/部署
sudo bridge-status
sudo test-inspect deploy | tail -3
sudo release-pipeline-status settle-test | head -8

# 验线上产物(🔴 只查字符串常量·遍历全部 chunk·带对照组)
B="https://test.tongban.love/settlement"   # 结算侧要带 /settlement 前缀
curl -s "$B/platform/minicup" -o /tmp/h.html
for c in $(grep -oE '/_next/static/chunks/[^"\\]+\.js' /tmp/h.html | sort -u); do
  curl -s --path-as-is "$B$c" -o /tmp/c.js
  echo "$(basename $c) 目标串:$(grep -c '要查的中文' /tmp/c.js) 对照组:$(grep -c '已知存在的中文' /tmp/c.js)"
done

第 8 节 · 相关文件

文件 内容
~/reports/h5-hero-final-mockup-20260910.html 头图定稿效果图(含深/浅底图按钮对比四格)
~/reports/pc-org-store-assets-mockup-20260910.html 门店物料弹框效果图
~/reports/brand-partner-plan-draft-20260909.md 品牌方合作方案思路稿
memory project-brand-partner-plan 品牌方方案台账(含待拍板项)
memory pitfall-verify-bundle-grep-string-not-identifier 验产物只能查字符串常量
memory cloud-test-env-facts 双部署链判据(9-09 复犯记账在文末)
memory how-to-selftest-platform-mobile-on-test 自测能力全指南