---
description: current main 登录入口在最大 Dynamic Type、Reduce Motion 与运行语义树下的证据、最小重构颗粒和截图视频验收合同
status: request_changes
updated: 2026-08-28
sources:
  - repo://ailoha-agent-iOS@6922f359ad08da70242e4ec0c5c4a1486bc2908d
  - brain://reports/ios-frontend-refactor-map/evidence/current-main-accessibility-runtime-2026-08-28/accessibility-runtime-audit.json
confidence: high for unauthenticated login; unknown for authenticated journeys and spoken VoiceOver behavior
sensitivity: internal
---

# current main 登录入口可访问性运行基线
<!-- brain-capture:ios-frontend-current-main-accessibility-runtime -->

## 一句话结论

登录页不是“完全不可访问”：Google、Apple 和同意协议三个核心动作能被运行语义树发现，同意状态也有 `Not agreed` 值。但两个设计合同已经被 current-main 代码和 Simulator 运行证据共同证实为失效：**系统字体调到最大后，品牌文字仍保持固定大小；系统打开 Reduce Motion 后，背景视频仍继续播放。**

这轮只到未登录入口。没有账号内 Home、Chat、Contact、Calendar、Widget 或 Live Activity 的运行收据，也没有真实 VoiceOver 的朗读顺序与 announcement 录音，所以不能把登录页结果外推成“整个 App 已通过”或“整个 App 都失败”。

另一台电脑可直接从 [Notion 完整案例](https://app.notion.com/p/3caa444a6c0081e692bcf325ba887fdb)接手：页面已内嵌 current-main 四张状态截图、三个声明式实现颗粒、Agent 顺序、8 图 3 视频和总体验收表。

## 工程认知颗粒：一个问题刚好对应一个可独立修改和验收的边界

### P0-1：字体偏好停在系统里，没有进入品牌字体

- **用户看到什么**：把系统文字调到最大，登录页标题、说明、协议和按钮仍像普通字号；视觉没有为低视力用户重排。
- **代码怎么堵住**：`Font.ailohaLora` 和 `Font.ailohaManrope` 最终都调用 `.custom(... fixedSize:)`。登录页还直接使用 `10.5`、`16` 等固定字号。系统的 Dynamic Type preference 没有成为这些品牌字体的输入。
- **运行事实**：同一 current-main Debug build 在 `large` 和 `accessibility-extra-extra-extra-large` 下都得到 40 个语义元素、6 个可操作目标、0 个滚动区域；最大字号截图没有出现应有的字号和布局变化。源码中的固定字体解释了这个现象。
- **怎么改**：先只给 DesignSystem 增加 `relativeTo: TextStyle` 的品牌字体 API；登录页按语义角色迁移标题、正文、按钮、协议，不全仓一次性替换。需要跟文字一起增长的间距和图标使用 `@ScaledMetric`；保留截图对比，逐屏迁移。
- **为什么这样改**：问题的 owner 是字体适配器，不是每个页面各写一套字号分支。先迁登录页能证明 API 是否正确，也把布局返工限制在一个完整旅程。
- **最小通过门**：Large 与 AXXXL 的标题/正文实际像素高度不同；AXXXL 下 Google、Apple、同意协议、Terms、Privacy、Support 全部可见或可滚动到；中英文、最窄支持机型均无关键裁切；页面语义树仍至少发现三个核心动作。

### P0-2：Reduce Motion 已开启，但自动循环视频没有收到这个状态

- **用户看到什么**：用户已经在系统里要求减少动画，登录页的全屏背景仍自动播放并循环。
- **代码怎么堵住**：`LoopingVideoPlayerView` 创建 `AVPlayer` 后无条件 `play()`，结束后又 `seek(.zero) + play()`；组件和登录页都没有 `accessibilityReduceMotion` 输入。
- **运行事实**：开启 Reduce Motion 后，一秒间隔的两张截图仍有 2,342 个像素超过 8 的差异，主要集中在视频上半区；该区域变化比例约 1.22%，而状态栏区域只有约 0.04%。这与无条件播放代码形成闭合证据。
- **怎么改**：把 `motionPolicy` 作为声明式输入传进背景媒体组件。Reduce Motion 开启时不创建或暂停 player，只显示同一资源的静态 poster；关闭时才自动播放。App 进入后台或页面离开时停止，回来时按 policy 恢复。
- **为什么这样改**：页面只声明“这里是装饰背景”，组件统一决定播放、暂停和静态 fallback，后续别的引导视频不必重复猜规则。
- **最小通过门**：Reduce Motion 开启后连续 3 秒的背景内容保持静止，登录能力和信息不丢；关闭后视频正常播放；切前后台 3 次无重复 player/observer、无声音、无白闪。

### P0-3：语义可发现不等于 VoiceOver 旅程已经通过

- **用户看到什么**：Google、Apple、同意协议应该能被读出、点开，并反馈同意状态；协议中的 Terms、Privacy、Support 也应该分别可激活。
- **已经好的地方**：运行语义树能发现 Google、Apple 和 Legal agreement；checkbox 有 `Not agreed` value。它们使用标准 `Button`，不是裸手势。
- **当前缺口**：Debug build 还暴露 `快捷登录`、`Local` 和一个空白 button target。当前工具只能抓运行语义树，不能证明真实 VoiceOver 的朗读顺序、协议链接拆分、alert 焦点、登录 loading/失败 announcement。Debug 目标也不能代表 Release。
- **怎么改**：把登录入口固定为一份语义合同：Release 只出现真实产品动作；协议链接是三个可独立命名的 action/link；checkbox 有 label、value 和足够触控面积；alert 出现后焦点进入标题，关闭后回到触发按钮；loading/失败有可感知状态。
- **为什么这样改**：测试的是用户能否完成登录，而不是统计 `.accessibilityLabel` 数量。
- **最小通过门**：Release + VoiceOver 从页面顶部单向 swipe，一次经过标题、说明、Google、Apple、同意、三个协议链接、验证说明；无空名称目标、无 Debug action；未同意登录时 alert 被读出，确认后状态变成已同意；每个关键目标可触范围至少 44×44pt，或由等价容器扩展到该尺寸。

### P1：Calendar 拖动与缩放仍需另开一个完整场景

`DraggableEventView` 的移动、顶部 resize 和底部 resize 都由长按/拖拽实现；源码没有等价的 `accessibilityAction`。resize handle 的触控 frame 已扩到 44×44，这是正向基础，但不解决 VoiceOver 无法执行拖拽语义的问题。下一颗粒应是“选中一个事件 → 向前/向后移动 15 分钟 → 增减时长 → 保存/撤销”的同一 authority action + 表单替代路径；在登录后的真实页面可达前，状态保持 **运行未验证**。

## 证据表

| 场景 | 设置 | 观察 | 结论边界 |
|---|---|---|---|
| Login baseline | Large；Reduce Motion 关闭 | 40 elements；6 targets；0 scroll area | 三个核心动作可被运行语义树发现 |
| Login + Reduce Motion | Large；Reduce Motion 开启；两帧相隔约 1 秒 | 视频区仍有可测变化；源码无条件播放 | 登录背景没有尊重系统偏好 |
| Login + 最大字号 | AXXXL；Reduce Motion 开启 | 40 elements；6 targets；0 scroll area；视觉布局未扩展 | 品牌字体没有形成 Dynamic Type 行为 |
| VoiceOver spoken path | 未运行 | AXe/xcui 未安装；本轮未改变机器工具链 | 朗读顺序、announcement、alert focus 仍 unknown |
| Authenticated journeys | 未运行 | 无测试账号内路径 | 不能外推 Home/Chat/Contact/Calendar |

机器可读证据见 [`accessibility-runtime-audit.json`](evidence/current-main-accessibility-runtime-2026-08-28/accessibility-runtime-audit.json)。四张原始截图位于同一证据目录，均记录 SHA-256。

## 给新 Agent 的实现顺序

1. 固定 current main SHA；先复跑本页三个登录场景，保存 baseline。
2. 只实现品牌字体 `relativeTo` API，迁移登录页，跑截图矩阵；不要顺手改全仓排版。
3. 只实现背景媒体 `motionPolicy`，用静态 poster 做 Reduce Motion fallback；跑 3 秒未剪视频。
4. 补 Release 语义合同和 44pt target；人工 VoiceOver 冷读一次。
5. 每颗粒独立 diff、独立证据、独立回滚。字体、motion、语义三个结果都通过后，才称“登录入口可访问性重构完成”。

## 截图与视频验收合同

### 必须交付的 8 张状态截图

命名必须包含 `revision-build-device-locale-textsize-motion-state`：

1. 英文 / Large / Reduce Motion off / 登录初始态。
2. 英文 / AXXXL / Reduce Motion off / 登录初始态。
3. 中文 / Large / Reduce Motion off / 登录初始态。
4. 中文 / AXXXL / Reduce Motion off / 登录初始态。
5. 英文 / AXXXL / Reduce Motion on / 静态 poster。
6. 中文 / AXXXL / Reduce Motion on / 静态 poster。
7. AXXXL / 未同意协议 / 登录 alert 已出现。
8. AXXXL / 已同意协议 / checkbox 状态与登录按钮可达。

每张截图旁边必须写：revision、build config、设备、OS、locale、content size、Reduce Motion、fixture、截图 SHA-256。只给拼图而没有原图不通过。

### 必须交付的 3 段未剪视频

1. **Dynamic Type**：从 Large 切到 AXXXL，重新进入登录页，逐项展示无裁切和可滚动性。
2. **Reduce Motion**：先展示设置已开启，再回 App 静置 3 秒；背景必须保持静止，按钮仍可用；再关闭偏好证明正常视频仍能播放。
3. **VoiceOver**：从页面顶部顺序 swipe 到登录和全部协议动作，触发未同意 alert、确认、再触发一次登录；画面保留 VoiceOver caption 或同步 transcript。

视频必须单镜头、显示系统设置变化、显示 App 回前台过程，不接受剪辑后只展示结果。

## 总体验收

| Gate | Pass | Fail |
|---|---|---|
| 字体 | Large→AXXXL 有真实缩放；关键内容可见/可达；中英窄屏通过 | 只改截图比例、关键 CTA 截断、协议不可达 |
| Motion | Reduce Motion on 时 3 秒静止；off 时可播放；前后台无泄漏/白闪 | 偏好开启仍自动播放、用隐藏信息换静止 |
| Semantics | Release 无空 label/Debug action；登录、协议、alert、状态可完整操作和感知 | 只证明语义树有节点，真实 VoiceOver 无法完成 |
| Evidence | 8 图、3 视频、semantic transcript 均绑定 revision/build/fixture/hash | 不知道跑的哪版；剪辑视频；缺少原始证据 |

## 反证与复查

- 新 revision 若品牌字体改为相对 text style，或 motion component 已消费 Reduce Motion，本页结论需重跑，不能靠旧 SHA 延续。
- Release build 若不含 Debug 目标，可把语义噪音降级为 Debug-only；仍需 Release snapshot 才能关闭。
- 真机 VoiceOver、AXXXL 或 Reduce Motion 行为若与 Simulator 不同，以真机结果为准并保留冲突。
- 复查日期：2026-09-30，或 iOS main SHA / OnboardingKit / DesignSystem 任一变化时提前复查。
