# PROGRESS · 西洋盘避让与移动端点击修复(2026-09-25) ## 最终整合复验补记 组合快照 `final-r4b` 已在 Linux Node22.23.2 / PostgreSQL17 验证:前端3894/3894、DB64/64,fail/skip/cancel/todo均0;tsc/lint/build各exit0,lint0error/127既有warning,首页Static。顶层及嵌套旧测试名无删除、新增失败0;完整首屏/入口增量/专属JS gzip分别+0.1612%/−0.4536%/−0.7984%。完整日志与快照hash见 `PROGRESS-three-fixes-integration-20260925.md` final-r4b节。 下文执行期状态保留作历史。组件几何/字符命中证据不冒充受控登录、整页移动端、真实Tab/读屏或部署验收;这些缺口保留,BUG-1033不提前resolved。 ## 状态与范围 本地实现和组件级验证完成,集成全量/独立复核/登录整页/部署待验收;未提交、未推送。BUG-1033由协调方分配(people预留1031/1032)。 - 工作树:`.worktrees/chart-western-fix-20260925`;分支:`codex/chart-western-fix-20260925`。 - 实际开工基线:`48fe4daf519dab2a5c6bf4b01dd513067de1647b`,不是任务书早先的`fabe0114`。 - 规格校正:任务书所写`frontend/src/lib/western-wheel-layout.ts`不存在;实际文件是`frontend/src/components/chart-page/western-wheel-layout.ts`,协调方已确认。 - 只改Western布局/SVG、测试/golden及文档。无引擎/API/people/报告业务修改,无依赖升级、workflow/main/DNS/stash操作。 - 用户硬门槛:**必须用Node22跑全量测试,并和开工时的基线逐条对比,新增失败为0才允许推送;改任何既有断言必须原值/新值/原因三栏。** 本单不以定向通过代替此门槛。 ## 决策与实现 ### D1 固定锚点,行星让位 保留ASC/MC的r162和+9°位置,共用同一坐标函数用于绘制与障碍盒。星座名和宫号亦作固定障碍。行星先保持既有11°松弛,再按距离代价搜索两层半径188/136及邻近角度,要求文字盒不交、完整在viewBox内、显示角仍至少11°、圆心距离大于命中半径+1。保留真实黄经用于刻度与引导线,未更改任何引擎数值。 独立复核发现真实窄宫的宫号互碰,因此最终不再豁免house-house:宫号保留真实宫中角度,默认r84,拥挤才径向尝试108/60/132/36。原golden仍全部r84,其既有半径断言未改。所有真实扫描样本保留,所有标签对均检查。 ### D2 扫描而非单一幸运样本 - 固定种子20260925、LCG的512张几何压力盘:ASC附近、MC附近、全周均匀随机三类,均匀宫头仅用于几何压力测试,不冒充引擎合同。 - 64张真实Swiss引擎虚构盘:保留原始响应及真实非均匀宫头,纬度±55°,无样本过滤。 - `MAX_OVERLAPPING_CHART_RATE=0.01`,并对固定回归集合额外断言实际重叠盘数为0。 - 渲染后读取实际inline字号,检查完整37个标签(11行星+26其他)、全部标签盒、边界;骨架和相位常显合同保留。 ### D3 按实际盘宽与真实字体验收 | 指标 | 原值 | 最终值 | | --- | --- | --- | | 375px页面盘宽 | 忽略左右页边距 | 375−16×2=343px | | 字号 | 17×343/520=11.21px | 19×343/520=12.53px | | 透明圆直径 | 44×343/520=29.02px | 68×343/520=44.85px | | 基线/符号字框 | middle / 约1em估算 | central / 符号2.2em,普通1.4em | | 点击归属 | 同组圆/线按行星顺序覆盖 | 所有按钮圆先画,所有文字后画;逐字符归属自身 | 真实本地Noto Symbols的文本盒约2.07em高,因此不能只按font-size估高。装饰引导线和刻度`pointerEvents=none`。可见文字层`pointerEvents=bounding-box`、点击同一回调,`aria-hidden`且无tabIndex;原透明圆组保留唯一键盘按钮/aria-pressed/标签,未产生重复Tab项。 ### D4 原始golden及陈旧文档 原Western fixture从视图键子集改为完整`build_tropical_natal_from_request`返回对象,测试内mapper转换。另存64份完整原始响应。仅JSON格式化及LF换行,无键值改造。BUG-1025与首页拆分CHANGELOG按历史行为→当前`/people`跳转更正,不抹掉历史。 ## 失败探索与复核账本 1. 初版估算几何扫描过,但Chrome65盘发现462对字框相交、7个中心命中错误。真实字体高度和middle基线导致漏算,后画装饰线也拦点击。修正字框/central/装饰线后65盘均0。 2. 高字框暴露512样本中的7个行星-宫号冲突;把实际宫号盒加入障碍后消除,不缩字。 3. 曾试`asc + offset*30 + skew*sin(offset*pi/6)`任意非均匀宫头,发现大量宫号互碰;这种生成器不是物理盘,未列正式引擎集。没有据此把全部验证换成均匀宫头:另补64张真实引擎完整响应。 4. 真实64盘初次Chrome有5对宫号互碰(2盘)。最初新测试临时跳过house-house;独立复核指出任务书要求任意标签,最终撤销例外并实现仅径向宫号避让。同样64盘保留,最终宫号碰撞0。 5. 独立复核指出只保护中心仍不够:真实扫描索引8/23/33/53/60可见文字末字符被邻星r34圆吞掉。改为先所有命中圆、后所有文字;逐字符`getExtentOfChar`中心`elementFromPoint`验证纳入可复跑脚本,最终0错误。没有把r34退回22来消红。 6. `git diff --check`首次报生成JSON的CRLF空白,统一为LF后复核;不改变raw数据。 ## 既有断言三栏 原有3个Western测试名称、断言表达式和chart-page-view原21项均未删除/替换。即便仅间接改变夹具或盒语义,也按三栏留账: | 原值 | 新值 | 原因 | | --- | --- | --- | | fixture为手工视图数组/键,测试直接读 | 完整引擎raw对象,测试内mapper构造视图 | AGENTS §7.4真实合同;11行星/12宫头真实值保留 | | `westernLabelBox`默认font17、高约1em | font19、符号2.2em/普通1.4em | 修正真实字体与343px缩放;盒更大是收紧检查,不是降容差 | | 单盘两两不交、11°、宫中角度/r84、骨架3圈12线无文字 | 原断言原样保留;追加512压力盘与64真实盘全标签扫描 | 提升覆盖,不删除幸运单盘合同 | | 本轮新真实扫描草稿暂排除house-house | 最终取消排除,检查全部标签对,阈值≤1%且固定集必须0 | 独立复核纠正范围;宫号径向避让而非豁免失败 | | 本轮新点击测试最初仅检查圆心 | 追加全部命中圆早于文字、唯一按钮数、装饰线不拦事件;Chrome逐字符hit-test | 独立审查发现可见字末尾被邻圆截获 | ## 本地验证 运行时:Windows、Node v22.23.2、Python3.11.7;依赖复用已有node_modules目录junction,未安装或升级。Linux全量由协调方独立执行。 | 检查 | 结果 | 边界 | | --- | --- | --- | | `npx tsx --test tests/western-wheel-layout.test.ts tests/chart-page-view.test.tsx` | 28/28,fail0 skip0 | 原24项保留,新增4项 | | `npx tsc --noEmit` | exit0 | 本地 | | `npm run lint` | 0 error / 127 warning | 既有无关警告,不顺手修 | | 512压力盘 | 全标签碰撞0 | 固定种子几何,不是引擎响应 | | 64真实引擎盘 | 全标签碰撞0 | 不过滤样本,不排除house-house | | Chrome129盘实际字体 | 碰撞0、宫号碰撞0、圆心与逐字符命中错误0 | 65真实含原golden +64压力;343px盘宽 | | Chrome实测 | 最小字12.53269px、命中直径44.85382px | 独立组件,不是登录页 | | LinuxNode22开工基线(协调方回报) | 3863/3863,fail0 skip0;DB61/61,tsc0 | 最终集成仍须名称逐条比较,不能用旧Node20失败豁免 | | Linux最终全量/build/Static/gzip | 待协调验收 | 未声称通过;不得推送 | | 登录页面/键盘/点选取消/部署health | 待验 | 见BLOCKED与真人清单 | 额外`pre_work_check.py --remote-timeout 8 --command-timeout 45`结果fail:`test_preflight_fragment_scan_reports_authority_layers_and_risk_buckets`在`tests/test_preflight_fragment_scan.py:64`要求`.workbuddy/skills/jyotish-vedic-astrology`镜像命中,但独立worktree无该镜像;Python运行、外部适配、远端可见性和其余扫描项通过。未修改Python生产文件或该断言;此失败不豁免前端门禁。 ## 复跑原始响应 仓库根目录运行;输入均为明确虚构的测试数据,不来自真实用户: ```python import json, random, sys from pathlib import Path sys.path.insert(0, 'scripts') from western_chart_engine import build_tropical_natal_from_request out = Path('frontend/tests/fixtures') one = build_tropical_natal_from_request(dict( year=1990, month=1, day=1, hour=12, minute=0, lat=39.9042, lon=116.4074, tz=8, house_system='P')) r = random.Random(20260925) scan = [build_tropical_natal_from_request(dict( year=1970+i%45, month=1+i%12, day=1+i%27, hour=i%24, minute=(i*13)%60, lat=r.uniform(-55,55), lon=r.uniform(-180,180), tz=0, house_system='P')) for i in range(64)] for name, value in [('western-1990-01-01-beijing.json', one), ('western-fictional-scan-20260925.json', scan)]: (out/name).write_bytes((json.dumps(value, ensure_ascii=False, indent=2)+'\n').encode()) ``` ## 复跑浏览器证据 `artifacts/western-browser-check.tsx`读取实际组件、globals.css和本地Noto字体,生成HTML,不接网络或用户数据。脚本及`artifacts/western-browser-result.json`作为复跑证据;生成HTML、Chrome profile、stderr和其他审查临时文件不纳入交付清单。 ```bash cd frontend NODE_PATH="$PWD/node_modules" npx tsx ../artifacts/western-browser-check.tsx # Chrome路径按本机安装调整,使用新建的专用临时profile,不借用登录profile chrome --headless --no-first-run --disable-gpu \ --user-data-dir=/tmp/western-check-profile --window-size=375,850 \ --virtual-time-budget=10000 --dump-dom \ file:///absolute/worktree/artifacts/western-browser-check.html ``` 等待字体就绪后`#result`必须charts129、collisions[]、houseOnlyCollisions[]、hits[]。页面交互、选择/取消及键盘需另按`docs/testing/chart-dasha-western-20260924.md`在受控登录环境执行。