Files
.pouch/skills/tester/references/schema.md
T

12 KiB
Raw Blame History

tester 目录字段

术语与命名理由见 concepts.md;本文件只列字段与约束。

项目根 .pouch/tester/:

catalog.yaml           分类、风险阶梯、session、变量、默认 Agent 目标
local.yaml.example     HOST、授权开关和 Agent 目标模板(默认 127.0.0.1)
local.yaml             本机覆盖,不提交
cases/<category>.yaml  一个分类一个文件(执行源)
cases.csv              给人看的扁平清单;只由 cases/*.yaml 生成,不包含运行结果
runs/<run-id>.yaml     每次运行快照(执行源);run-id 必须唯一
runs/*.csv             同一次运行的成绩单;generate_run_csv.py 从对应 yaml 生成

两类用例共用同一套 cases/runs 和五态报告,不另造成绩单。新目录显式声明顶层 test_type: journey | integration;旧目录没有该字段时按已有 client_suite/journey 或 integration_suite 推断。category 仍是文件/执行顺序容器,不被套件字段替代。

catalog.yaml

字段 含义
categories {id, title, status_probe?} 列表,id 与 cases/<id小写>.yaml 对应;列表顺序即 select / 执行顺序。status_probe 见下
risks 从低到高,只能是 readonly → mutating → destructive 的一段,且以 readonly 开头。含义见 levels.md
default_max_risk 未指定时的运行上限,必须是 risks 里的值
execution_profile standard(默认)或 isolated-full。后者只用于隔离可重置环境,保留 risk 语义但不按 risk/authorize/gate 过滤 active 用例;安全边界由 preflight capability 与 cleanup/rollback 契约承担
vars 可替换变量,如 API_BASE: http://${HOST}:8095
artifacts 可选的移动产物身份契约。按 android / ios 声明 required 和 package / bundle_id;每轮文件路径或下载地址由调用方提供,不提交临时产物路径。
authorize 风险名 → 环境变量名。该档执行前变量必须为 true(readonly 不需要)
gates 可选。项目细分闸名 → 环境变量。用在用例的 gate 上,不要拿它代替 risk
sessions 可复用会话。kind: browser / mobile;reuse: run(本轮结束关掉)或 persist(probe 活着就附着)
id_pattern 用例 id 正则
run_together 可选。成组执行:[{ids: [TC-…, TC-…], continue_on_fail: true}]。点到组内任一条,select 会按 ids 顺序把整组扩进命中列表。continue_on_fail: true 时组内前一条产品 fail 仍跑后一条(返回/收尾)。一个 id 只能属于一组。
status_probe 可选。顶层默认值,一个分类级前置条件:{url, stop_if: {字段: [命中值]}}。运行前请求 url,响应命中任一 stop_if 条件即视为前置不满足。分类项可用同名键覆盖:缺省继承顶层、false 关闭、mapping 整体替换。命中或不可达只影响用它的分类,不是产品失败。业界对应 pytest 的 session fixture / Robot 的 Suite Setup。select 会按分类返回解析后的生效值,url 已用 vars 展开
client_suites 可选的标准套件声明;出现时必须完整包含 client-smoke、client-regression、safety。缺省运行仍按 tag 兼容旧目录
integration_suites 可选的集成套件声明;标准值为 api-contract、authorization、build-contract

isolated-full 不得把风险字段改成 readonly,也不得把 AUTHORIZE_ALBUM、 AUTHORIZE_PASSWORD、IME_PINYIN 等变量当成能力门禁。移动用例必须通过 test-preflight 的真实相册 picker、照片权限/测试图片和中文拼音 composition/candidate 检查。

local.yaml 与环境变量覆盖 HOST 和授权开关。模板中的 HOST 默认是 127.0.0.1;远程目标必须显式覆盖。查找顺序:环境变量 > local.yaml > catalog.yaml 的 vars。

agent

catalog.yaml.agent 是可提交的默认 Agent 目标,local.yaml.agent 对其做浅层覆盖。 它不参与 HOST 变量解析,也不会把远程机器路径写入环境变量。机器路径和临时 Agent 选择优先写在不提交的 local.yaml。

字段 含义
environment Orca 保存的远程环境选择器;空值使用当前环境
host 目标机器标识,默认 local
project Orca project id 或名称;也可由 terminal id 自动解析
path 目标机器上的项目路径;空值表示当前项目根目录
role Agent 角色,tester 固定为 test
cli codex / cursor-agent / grok / omp / pi
tier standard / strong
model 精确模型 ID;null 表示使用 CLI 默认模型
reasoningEffort low / medium / high / xhigh 或 null
permissionMode read-only / workspace-write

用户给 project id、项目名称或 terminal id 时,tester 先解析并写入 local.yaml.agent, 再展示更新后的 Agent/环境/项目/目录生效列表。每轮创建新 terminal,不复用既有 terminal;运行结束用 orca terminal close --terminal <handle> 关闭本轮创建的 terminal。 运行快照保存解析后的 Agent、目标、worktree 和 terminal handle。旧版 execution 字段 只作为兼容输入读取,不再作为新配置写出。详见 execution.md。

运行记录使用 UTC 时间加随机后缀命名,例如 20260920T101530Z-smoke-a13f9c.yaml,并在 YAML 顶层保存同一个 runId。 不要使用固定的 latest.yaml 或覆盖已有运行文件。

一条用例

写在对应分类文件的 cases: 列表里。

字段 必填 含义
id 是 匹配 id_pattern
test_type 新用例是 journey 或 integration;缺省兼容旧目录并按字段推断
category 是 必须等于文件声明的 category
title 是 短名
what 是 一句可观察的「测什么」
lifecycle 是 active / pending / retired。pending = 暂缓,仍保留在目录里但不执行,原因写在 notes
tag 是 smoke / full / slow,判定见 levels.md。tag=smoke 只能配 risk=readonly
risk 是 readonly / mutating / destructive
gate 否 项目细分闸,必须在 catalog gates 里;risk=readonly 不要填
driver 否 script / browser / mobile;automation=manual 时禁止填
automation 否 automated(默认)/ assisted / manual,见 concepts.md
session browser/mobile 必填 指向 catalog sessions 的键
how 是 怎么测,见下
expected 是 怎么过,至少一条 {kind, value}
maps_to 否 对人文档的功能项 id
assume 否 额外跳过条件(环境变量表达式)。不要重复 risk / gate 已覆盖的授权变量,否则 validate 报错
depends_on 否 依赖的 testcase id 列表;依赖 fail/environment-fail/not-run 时本条写 not-run 和 blocked_by,独立用例继续
setup 否 人话前置
teardown 否 跑完回退
notes 否 备注

集成测试用例契约

test_type: integration 的用例不创建 browser/mobile session,也不能声明 platform 或 客户端 journey。必须有 integration_suite(迁移期可用 suite)且值为 api-contract、authorization 或 build-contract;fixture 必须是非空 mapping; request、input、call、integration 之一或旧式 how 用于描述调用;expected 是 协议/数据断言。mutating/destructive 集成用例必须提供 cleanup.steps 或 cleanup.run(只读探针可用 required: false + reason)。

选择 --suite api-contract 或 --test-type integration 才会进入集成阶段;无显式类型 时的默认选择不会包含 integration。

客户端旅程用例契约

声明 client_suite 后,以下字段都必须存在;catalog.py validate 和 select 使用同一 套检查。契约缺失是 preflight: blocked,不生成逐条产品失败。

字段 必填 约束
client_suite 是 client-smoke、client-regression 或 safety;安全套件必须显式选择,不属于默认 smoke/full
journey.goal 是 用户目标,不写接口目标
journey.entry_state 是 启动/登录前的可观察入口状态
journey.actions 是 非空用户操作列表;真实 App/browser 驱动从这里开始
journey.assertions 是 非空可观察 UI 断言列表;最终业务状态可另由 expected 的 api-field/api-status 佐证
journey.final_state 是 旅程完成后的业务状态
journey.failure_policy 是 stop 或 continue;默认不隐式吞掉前置失败
fixture 是 mapping,至少有 account;账号和数据由 app catalog 提供,skill 不写具体账号
session 是 复用的 browser/mobile session 名,必须在 catalog.sessions 声明
cleanup 是 mapping,必须有非空 steps/run;只读旅程也要用 required: false + reason 显式说明无需清理
platform 是 android/ios 的字符串或列表,不能重复;平台差异只能进入执行适配层

一个最小形状如下(值是占位符,不是 app 规则):

client_suite: client-smoke
platform: [android, ios]
journey:
  goal: "用户完成一个可观察的客户端目标"
  entry_state: logged_out
  actions: ["启动客户端", "输入测试账号并登录", "完成目标操作"]
  assertions: ["看到目标页面", "看到成功提示"]
  final_state: "目标状态已保存"
  failure_policy: stop
fixture:
  account: test-role
  data: []
session: mobile
cleanup:
  steps: ["删除本轮 run-id 创建的数据"]

账号登录属于 session 初始化:正确测试账号登录失败是产品 fail;设备、产物或服务 不可达才是 environment-fail。fixture/cleanup 缺失必须在启动、登录和任何旅程操作前 阻断。旅程失败后,尚未轮到的用例记 not-run;风险、生命周期或明确范围排除记 skipped。清理失败单独写入运行快照的 cleanup 证据,不改造为一个新的 result 值。

how

按 driver 分派;automation=manual 时没有 driver,只有 how.steps(人工步骤)。

  • script:how.run 是一条可在项目根执行的命令(可多行脚本)。没有 run 时 Agent 按 how.steps 做,仍不得发明未写明的请求。
  • browser:how.url + how.steps。expected.kind 用 visible-text / url / interaction。
  • mobile:how.steps,挂到 session 指定的模拟器。expected 同样是可观察信号。

可选 how.timeout,秒,默认 60。

automation=assisted 时,至少一个 how.steps 条目要以 [人工] 开头(写在 YAML 里要加引号,[ 开头会被当成流式序列)。

expected.kind

api-status / api-field / script-exit / visible-text / url / interaction

判定

pass / fail / environment-fail / skipped / not-run

运行失败回流

run YAML 的 results 必须保留每条 testcase 行。失败可在顶层 defects(兼容别名 test_issues)追加:

defects:
  - testcase: TC-CLIENT-001
    issue_type: product # product | test
    expected: "候选词可选择"
    observed: "composition 成功但候选列表为空"
    artifact_hash: sha256:...
    environment: "Android emulator API 35 / tester.android"
    evidence_path: .pouch/tester/evidence/TC-CLIENT-001.png
    reproduction: "打开相册后输入 nihao"
    next_step: "开发修复候选词渲染后 targeted rerun"

PR 触发的 run 可带 feedback 计划:先更新 PR/关联 issue,再通知 dispatcher 重新分配开发; 需求/bug 触发则 route 直接为 development。tester 只记录计划,不隐式调用远端写操作。