# tester 运行 只在用户要跑测试时读本文件。 ## 1. 选范围 未指定范围 → `--tag smoke`,风险上限 = `default_max_risk`,`automation` 默认只跑 `automated`。 用户说分类、id、tag、风险上限时,原样传给 select: ```bash python3 /scripts/catalog.py select --root \ [--category CAT] [--id ID]... [--tag smoke|full|slow] \ [--max-risk ] [--driver script|browser|mobile] \ [--automation automated|assisted|manual|any] ``` `--automation` 默认 `automated`(需人工的条目会被跳过,并在 JSON `skipped` 里说明);用户明确要求现场配合时用 `assisted`,`any` 表示不按人工参与度筛。 `select` 的 JSON 字段:`max_risk` / `automation` / `count` / `vars`(已展开的变量,用来替换 `how` 里的 `${…}`)/ `skipped` / `run_together` / `status_probe`(按分类,`url` 已展开)/ `cases`。 `select` 已排除 `retired` 和风险高于上限的条目(后者若用户点了具体 id,会在 JSON 的 `skipped` 里说明,不执行)。 若 catalog 有 `run_together`,命中组内任一条就把整组按 `ids` 顺序扩进列表(JSON 带 `run_together`)。这不是擅自扩大范围。 无命中:停下说明筛选条件,不要扩大范围。 ## 2. 运行前闸 - `HOST` 未设(环境变量 / `HX_TEST_HOST` / `local.yaml` 都没有):全部停,environment-fail。 - 命中条的 `risk` 在 catalog `authorize` 里有对应变量:变量不是 `true` 则该条 `skipped`。有 `gate` 时还要 `catalog.gates` 对应变量为 `true`;`assume` 不成立同样 `skipped`。即使用户点了 id 也不执行。 - 授权/假设不成立是**主动不跑**(`skipped`),不是 `not-run`:这是我们决定不跑,不是没轮到。 - `status_probe` 是**分类级前置条件**(业界对应 pytest 的 session fixture / Robot 的 Suite Setup)。用 `select` 返回的 `status_probe` 解析生效值,不要自己读 catalog 猜。返回的 `probe.url` 已用 `vars` 展开,直接请求即可;`select` 同批返回 `vars`: | `categories[].status_probe` | 生效探测 | |------------------------------|----------| | 未声明 | 继承顶层 `catalog.status_probe`(`source: global`)| | `false` | 该分类不做闸(`source: disabled`)| | mapping | 整体覆盖顶层,不合并(`source: category`)| - 同一生效探测一次运行只请求一次,结果复用。 - 探测不可达:用它的分类标 environment-fail,其余分类照跑。 - 命中 `stop_if`:把用它的分类标 environment-fail 并记 `observed` 值,其余分类照跑;所有选中分类都被挡住时,整轮结论才是 environment-fail。 ## 3. Session 看命中条用到的 `session` 键: - 尚未初始化:按 catalog `sessions..init` 做。`reuse: persist` 的先 `probe`,活着就附着。 - 本轮已初始化:直接用,不要重开浏览器或模拟器。 - `reuse: run`:整轮结束再关。`persist`:不关。 - 中途 session 挂了:后续同 driver 标 environment-fail,不要标产品失败。 ## 4. 执行 按 select 返回的顺序,一条一条来。select 按 `catalog.yaml` 的 `categories` 顺序,同一分类内按该 yaml 列表顺序(不是文件名字母序)。默认失败即停(产品 `fail` 或探测到的不安全状态)。用户说继续 / keep-going 才往后跑。 例外:当前条和下一条同属 `run_together` 且该组 `continue_on_fail: true` 时,前一条产品 `fail` 仍跑后一条。`environment-fail` 仍整轮停。 **automation** - `automated`:Agent 端到端执行。 - `assisted`:照常驱动,但遇到以 `[人工]` 开头的 `how.steps` 时停下,请现场人员执行并回报,确认后再继续。无人值守时该条记 `not-run`。 - `manual`:没有 `driver`,`run-script` 会直接返回 `not-run`。只能由人执行、回报结果,Agent 负责记录。 **script** 有 `how.run`: ```bash python3 /scripts/catalog.py run-script --root --id ``` `run-script` 只跑命令,返回 `executed` + stdout/exit(或 skipped / environment-fail)。**pass/fail 仍由 Agent 对照 `expected` 判定**,不要把 curl 退出码 0 当成产品通过。 没有 `run`:按 `how.steps` 做,证据对照 `expected`。不要发明 steps 里没有的调用。 **browser / mobile** 挂到已有 session,执行 `how.steps`,对照 `expected`。必须留下可见文本、URL 或交互证据。 ## 5. 记录与报告 每条:`id, result, evidence, notes`。`result` 只能是 `pass` / `fail` / `environment-fail` / `skipped` / `not-run`。`skipped` 是主动不跑(retired / pending / 超风险上限 / 未授权 / `assume` 不成立),`not-run` 是没轮到(失败即停后剩下的 / 被前置整组挡住的 / 需人工而无人值守的)。 写入 `.pouch/tester/runs/-<范围>-<随机后缀>.yaml`,可用 `generate_run_csv.new_run_id(<范围>)` 生成同名 `runId`。记录包含唯一 `runId`、筛选条件、HOST 是否已设(可以写 HOST 值)、session 是否复用、每个分类的 `status_probe` 生效值与观测结果(`source` / `disabled` 原因 / `hit` / `observed`)、逐条结果。记录文件只创建一次,不覆盖已有文件。立刻用同一快照生成 CSV,不要手改: ```bash python3 /scripts/generate_run_csv.py --root --run ``` 这会写出与快照同名的 `.pouch/tester/runs/.csv`(`executed=yes|no`),不会修改 `cases.csv`。对话里两个路径都报。 对话报告: ```text ## tester 运行:完成 | 部分完成 | 阻塞 范围: … 风险上限: … session: browser=复用|新开|未用;mobile=… 计数: pass=N fail=N environment-fail=N skipped=N not-run=N 失败: id + 一句证据 跳过: id + 原因 快照: .pouch/tester/runs/.yaml 成绩单: .pouch/tester/runs/.csv 下一步: 一句话 ```