修复移动验收门禁漂移(07-27-yang-jun-reimbursement-readiness)
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s

这个提交包含在:
2026-08-01 16:28:14 +08:00
父节点 3bfcbbfc91
当前提交 5dac336fbf
共修改 8 个文件,包含 94 行新增和 13 行删除
@@ -2053,3 +2053,57 @@ hierarchy without turning every page into a bespoke Tailwind card system.
- Focused Playwright coverage for changed finance/admin pages. The Wave4
baseline test is `client/tests/e2e/pc-finance-admin-visual-wave4.spec.ts`.
- UI design rules check when changing these shared classes.
## Scenario: Frontend Acceptance Spec Gate Registration
### 1. Scope / Trigger
- Trigger: a frontend E2E spec is treated as a current acceptance contract rather than historical evidence or a manual-only diagnostic.
### 2. Signatures
- Manifest entry: `scripts/qa/route-manifest.json` → `acceptanceSpecs[]`.
- Executable gate: `bash scripts/qa/run-local-candidate.sh list|focused|full`.
### 3. Contracts
- A current acceptance spec must be referenced by an executed gate; merely existing under `client/tests/e2e/` is not coverage.
- `list` must resolve the spec, while `focused` or `full` must execute it and reject failed or skipped acceptance results.
- DOM discovery may be dynamic to avoid duplicating selectors, but the expected business set, order or invariant must remain explicit. Never accept whatever the page happens to render.
- Historical or unowned specs must be deliberately classified for later connection or deletion; do not silently present them as active coverage.
### 4. Validation & Error Matrix
- Manifest entry missing or invalid → flow-coverage gate fails.
- Acceptance spec skipped, failed or timed out → local-candidate result gate fails.
- Dynamic collection with no fixed expectation → review failure even if the test is green.
- Gate fixture cannot execute a newly called child script → fixture test fails and the child script must be added through command discovery or explicit setup.
### 5. Good/Base/Bad Cases
- Good: discover current action tiles from the grid, then assert the fixed role-specific key/label set and layout invariants.
- Base: a stable single control uses a direct `data-testid` assertion and is listed in `acceptanceSpecs`.
- Bad: count whatever matching nodes exist, assert only their individual dimensions, and leave the spec outside every runner.
### 6. Tests Required
- `node --test scripts/qa/tests/check-flow-coverage.test.mjs scripts/qa/tests/check-minimal-profile.test.mjs scripts/qa/tests/verify-local-candidate-results.test.mjs`.
- `bash scripts/qa/run-local-candidate.sh list` must list the spec.
- `bash scripts/qa/run-local-candidate.sh focused` or `full` must finish with zero failed/skipped acceptance tests.
### 7. Wrong vs Correct
#### Wrong
```ts
const actions = collectVisibleActions();
for (const action of actions) expect(action.height).toBeGreaterThanOrEqual(44);
```
#### Correct
```ts
const actions = collectVisibleActions();
expect(actions.map(({ key, label }) => ({ key, label }))).toEqual(EXPECTED_ACTIONS);
for (const action of actions) expect(action.height).toBeGreaterThanOrEqual(44);
```
@@ -8,6 +8,14 @@
- [x] 聚焦 Playwright 覆盖列表筛选返回、审批任务返回、直接打开降级、金额格式与移动单一入口;再运行 typecheck、build 和治理门禁。
- [x] 本轮只做本地实现与验证;未获部署批准前不发布、不修改生产配置或真实业务数据。
## 0.2 R5 移动契约与门禁收口(本轮)
- [x] 修正 R5 首页指标采集:从 `mobile-action-grid` 的直接入口动态取得 key 与布局,不再维护已经失效的旧 key 列表。
- [x] 对经理测试角色明确断言有序入口集合为 `new-reimbursement / capture / leave / purchase`,保留 44px、单行、SVG、边界和无重叠检查。
- [x] 将 R5 登记到 `route-manifest.json` 的 `acceptanceSpecs`,使 `run-local-candidate.sh` 的 list/focused/full 都能解析并执行该用例;不重复加入另一个门禁造成同轮双跑。
- [x] 运行 R5 双设备、flow coverage/本地候选资产解析、前端 typecheck/build 与 Trellis 治理门禁;记录约 18 个其他孤儿 spec 为后续治理,不在本轮扩范围。
- [x] 修正上一轮证据中的错误表述:页面实际仍有四个入口,只有旧采集器因 key 漂移看见两个;本轮未推送、未部署前不宣称线上已修复。
## 1. 生产写入前门禁
- [x] 只读复核活动 server 构建标识、Compose 项目、4 个 systemd service 当前 `BUILD_SHA`、timer enabled/active、最近源端备份与 ARM 新鲜度;输出仅限状态和计数。
@@ -352,5 +360,8 @@
- 只读 review:按 workflow task、PaymentBatchItem/batch、回单计数三源逐项复核映射与权限;修正“workflow 已通过但尚未建批次”原本无当前节点的问题,使其明确落在“待财务创建付款批次”。确认未来 checker 不预填、普通申请人无批次链接、共享批次不暴露其他单据/金额/材料;review 未修改状态机、权限矩阵或生产数据。
- 最终治理:task validate、Trellis governance、process contract、敏感扫描和 `git diff --check` 通过;文档审计 0 error、1 条既有汇总 warning(22 个历史未登记文件)。本步骤未部署、未推送、未修改生产配置、真实报销状态、付款批次、回单或业务数据。
- PC/移动 UX 最小收口:PC 从带 `status/page/scope` 的报销列表进入审批任务后可返回同一查询,从审批任务进入报销详情后显示“返回审批详情”,直接打开详情显示“返回报销列表”;业务动作区不再重复列表入口。共享 `formatMoney` 统一总额、明细、发票和标准提示为人民币两位小数;移动底栏只保留“提交审批”,材料区继续保留“添加发票”。
- UX 聚焦验证:Wave3 返回/金额/视觉相关 5 项通过,R111 PC/企微材料相关 2 项通过;typecheck 与生产 build 通过,截图确认 PC 返回位于标题上方、移动底栏为单一主按钮。旧 R5 综合移动用例 2 项在进入报销详情前因首页快捷入口既有期望“至少 4 个”而失败,实际为 2 个;该失败不由本轮改动引起,不作为本轮详情回归失败,也未修改其首页基线断言。
- UX 治理:task validate、Trellis governance、process contract、敏感扫描与 `git diff --check` 通过;文档审计 0 error、1 条既有未注册文档汇总 warning。稳定的 PC 单层来源返回和共享人民币展示合同已写入 `frontend-react-vite-design` spec。本步骤未部署、未推送、未修改生产配置或真实业务数据。
- UX 聚焦验证:Wave3 返回/金额/视觉相关 5 项通过,R111 PC/企微材料相关 2 项通过;typecheck 与生产 build 通过,截图确认 PC 返回位于标题上方、移动底栏为单一主按钮。旧 R5 综合移动用例 2 项在进入报销详情前因采集器仍查 `approvals/reimbursements/me` 等旧 key 而只识别出 2 个入口;页面对该经理角色实际仍渲染“新建报销、上传票据、请假记录、采购”4 项,上一轮“实际为 2 个”的表述已在本轮勘误。
- R5 门禁收口:测试从常用动作宫格动态采集入口,但固定断言经理角色的 4 项 key/标签集合,并保留双设备 44px、单行、SVG、边界和无重叠检查;详情返回按当前统一详情壳断言为按钮。R5 单跑 2/2 通过,并登记到 `route-manifest.json` 的 `acceptanceSpecs`。
- 候选门禁修复:`run-local-candidate.sh list` 首轮暴露隔离夹具漏建普通 `bash child-script`,修正为按命令行同时发现 `bash` 与 `bash -n` 子脚本;focused 首轮随后揭示 Wave3 合同页在 Radix 菜单仍打开时等待背景“筛选”按钮至 300 秒超时,改为先完成页面操作、最后验证“更多/导出 CSV”。最终本地候选 50 项、10 个核心 witness 全通过,0 failed、0 skipped、0 unexpected,状态为 `FOCUSED_BROWSER_PASS`。
- 门禁治理复验:QA Node 测试 52/52 通过;flow coverage 将 acceptance spec 从 7 项增至 8 项,8/8 有效且 0 blocking gap;前端最终 `typecheck` 与生产 build 明确 `exit=0`,PWA 产物生成完成。
- UX 治理:task validate、Trellis governance、process contract、敏感扫描与 `git diff --check` 通过;文档审计 0 error、1 条既有未注册文档汇总 warning。稳定的 PC 单层来源返回、共享人民币展示及 acceptance spec 必须接入真实门禁的合同已写入 `frontend-react-vite-design` spec。本步骤未部署、未推送、未修改生产配置或真实业务数据。
@@ -57,6 +57,8 @@
- PC 报销详情必须提供位于标题左上方、来源感知且可预测的返回入口:从带筛选的报销列表进入时返回原列表 URL,从审批任务进入时返回原审批任务;刷新、收藏或非法来源降级到报销列表。返回入口不得继续混在提交、催办、打印或“更多”等业务动作中,来源只接受受信任的 OA 内部报销列表或审批任务路径。
- PC 与移动报销详情的人民币金额必须复用 `client/src/lib/displayFormat.ts` 中的共享格式化函数,统一显示货币符号、千分位和两位小数;缺失或非法金额显示中性占位,不把缺失值伪装成 0 元。
- 移动草稿详情的“添加发票”只保留在“报销材料”区;底部固定动作栏只保留“提交审批”。不删除发票上传/选择能力,不改变提交前检查、材料权限或审批状态机。
- 旧 R5 真机反馈用例必须跟随当前移动首页信息架构:从常用动作宫格动态采集实际入口,但对经理测试角色固定断言“新建报销、上传票据、请假记录、采购”四项完整集合,并继续验证触控尺寸、单行标签、SVG 图标和无重叠;不得把动态采集写成“采到什么就接受什么”的重言测试。
- R5 不得继续作为无人执行的孤立 spec。将其登记到现有本地候选门禁的 acceptance spec 清单,使 `run-local-candidate.sh` 每次候选回归都执行;其余未被任何门禁引用的历史 E2E 仅记录为后续测试资产治理范围,本轮不批量接入、跳过或删除。
## Scope
@@ -109,6 +111,7 @@
- [x] PC 从报销列表或审批任务进入报销详情后,标题左上方显示明确的来源返回入口;返回可恢复列表查询参数或原审批任务,直接打开详情则安全回报销列表,业务动作区不再重复显示“报销列表”。
- [x] PC/移动报销详情的总额、明细和发票金额统一使用共享人民币格式,覆盖整数、小数、千分位、空值和非法值。
- [x] 移动草稿详情“报销材料”区保留“添加发票”,底部固定栏不再重复该动作且“提交审批”仍可见、可达并满足安全区/触控尺寸合同。
- [x] R5 双设备用例按当前四项常用动作合同通过,且已进入本地候选门禁的 acceptance spec 清单;门禁资产解析能列出该 spec,不再依赖手工全目录执行才发现漂移。
## Out of Scope