@epoint-testtech/ep-stage-skill 0.0.16 → 0.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/codex-skill/ep-stage/glue-generate-testcase/SKILL.md +7 -6
  2. package/codex-skill/ep-stage/glue-run-test/SKILL.md +97 -34
  3. package/codex-skill/ep-stage/glue-run-test/references/ai-runtime-loop.md +15 -9
  4. package/codex-skill/ep-stage/glue-run-test/references/crud-pipeline.md +10 -3
  5. package/codex-skill/ep-stage/glue-run-test/references/gap-review-protocol.md +11 -0
  6. package/codex-skill/ep-stage/glue-run-test/references/playwright-cli-odav.md +13 -2
  7. package/dist/src/cli/calibrate.d.ts +75 -0
  8. package/dist/src/cli/calibrate.d.ts.map +1 -0
  9. package/dist/src/cli/calibrate.js +318 -0
  10. package/dist/src/cli/demote.d.ts +53 -0
  11. package/dist/src/cli/demote.d.ts.map +1 -0
  12. package/dist/src/cli/demote.js +111 -0
  13. package/dist/src/cli/index.d.ts +5 -3
  14. package/dist/src/cli/index.d.ts.map +1 -1
  15. package/dist/src/cli/index.js +45 -6
  16. package/dist/src/cli/run-report.d.ts +6 -0
  17. package/dist/src/cli/run-report.d.ts.map +1 -1
  18. package/dist/src/cli/run-report.js +161 -147
  19. package/dist/src/cli/run.d.ts +51 -0
  20. package/dist/src/cli/run.d.ts.map +1 -1
  21. package/dist/src/cli/run.js +229 -27
  22. package/dist/src/contracts/glue-contract-v1.d.ts +37 -1
  23. package/dist/src/contracts/glue-contract-v1.d.ts.map +1 -1
  24. package/dist/src/extractors/code-list-json5.d.ts +29 -0
  25. package/dist/src/extractors/code-list-json5.d.ts.map +1 -1
  26. package/dist/src/generators/stage-skeleton-script.d.ts +30 -1
  27. package/dist/src/generators/stage-skeleton-script.d.ts.map +1 -1
  28. package/dist/src/generators/stage-skeleton-script.js +74 -11
  29. package/dist/src/runtime/ai-runtime-trace.d.ts +6 -0
  30. package/dist/src/runtime/ai-runtime-trace.d.ts.map +1 -1
  31. package/dist/src/testcase/contract-testcase-assembler.d.ts +23 -4
  32. package/dist/src/testcase/contract-testcase-assembler.d.ts.map +1 -1
  33. package/dist/src/testcase/contract-testcase-assembler.js +204 -27
  34. package/dist/src/testcase/query-component-map.d.ts +51 -0
  35. package/dist/src/testcase/query-component-map.d.ts.map +1 -0
  36. package/dist/src/testcase/query-component-map.js +64 -0
  37. package/dist/src/validation/contract.d.ts.map +1 -1
  38. package/dist/src/validation/contract.js +45 -3
  39. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: glue-generate-testcase
3
3
  description: 使用时机:当用户对某需求要「生成用例 / 准备测试场景 / 钻探上游需求生成胶水冒烟用例」或显式触发 `/glue-generate-testcase <code_list.json5路径>` 时使用。本 skill 包装 `@epoint-testtech/ep-stage-skill` CLI 的 `testcase` 子命令,并负责自然语言映射、缺数据引导、Step 5 凭据交互确认。
4
- version: 2026-08-12+925f4c4
4
+ version: 2026-08-26+38131e2
5
5
  argument-hint: "<code_list.json5绝对/相对路径>"
6
6
  ---
7
7
 
@@ -121,11 +121,11 @@ Step 4 成功后,skill 读 CLI 产出的 `credentials.template.json5`(行数
121
121
  > 2. **仅生成 template,自己后续填** — 退出后请拷贝 `credentials.template.json5` → `credentials.json5` 并填值
122
122
  > 3. **跳过,使用全局 systems[] 缓存复用** — 自动从 `cachedSystemsHit` 命中缓存生成 `credentials.json5`(缺失角色 fallback 引导 C,留给 glue-run-test)
123
123
 
124
- 三分支处理:
124
+ 三分支处理(**落盘字段铁律**:`credentials.json5` 每条必须含 `url`(= 登录页地址)且非空——运行库 `loadCredentials` 只读 `url / username / password`,不识别 `loginUrl`;缓存/交互中的 `loginUrl` 落盘时必须同时映射为 `url`,`loginUrl`/`directUrl` 可作冗余字段保留。缺 `url` 会在 run 阶段以 `page.goto(undefined)` 形式爆掉):
125
125
 
126
- - **选 1**:skill 顺序问每条角色的直达链接(directUrl)/ 登录地址(loginUrl)/ 系统名称(systemName)/ 角色(role)/ 账号(username)/ 密码(password)(free text)。直达链接问题必须说明其来源是 `view-source:` 后面的页面地址。收集后先展示摘要给用户确认;确认后写 `<需求名>/credentials.json5`(gitignore,非 template),`<需求名>/testcase.json5.testAccess` 只保留 `credentialRef: 'credentials.json5'` 和 `requiredRoles`,**回写**全局 `~/.ep-stage/projects.index.json5` 的 `systems[].credentialsCache`(按 loginUrl 归并,跨需求复用)。
126
+ - **选 1**:skill 顺序问每条角色的直达链接(directUrl)/ 登录地址(loginUrl)/ 系统名称(systemName)/ 角色(role)/ 账号(username)/ 密码(password)(free text)。直达链接问题必须说明其来源是 `view-source:` 后面的页面地址。收集后先展示摘要给用户确认;确认后写 `<需求名>/credentials.json5`(gitignore,非 template;登录地址同时落 `url` 与 `loginUrl` 两个字段),`<需求名>/testcase.json5.testAccess` 只保留 `credentialRef: 'credentials.json5'` 和 `requiredRoles`,**回写**全局 `~/.ep-stage/projects.index.json5` 的 `systems[].credentialsCache`(按 loginUrl 归并,跨需求复用)。
127
127
  - **选 2**:保留 template;提示"请编辑 `credentials.json5` 后再跑 `/glue-run-test`",进入 Step 6。
128
- - **选 3**:从 `systems[].credentialsCache` 拼出 credentials.json5,缺失角色用 template 占位符保留;`<需求名>/testcase.json5.testAccess` 只保留 `credentialRef: 'credentials.json5'` 和 `requiredRoles`,不写明文账号密码。
128
+ - **选 3**:从 `systems[].credentialsCache` 拼出 credentials.json5——缓存条目的 `loginUrl` 必须映射为 `url` 字段,模板字段(directUrl / url / systemName / role / username / password)一个不可丢;缺失角色用 template 占位符保留;`<需求名>/testcase.json5.testAccess` 只保留 `credentialRef: 'credentials.json5'` 和 `requiredRoles`,不写明文账号密码。
129
129
 
130
130
  ### Step 6 — 校验产物完整性 + 审阅 testcase.md 单表
131
131
 
@@ -134,6 +134,7 @@ Step 4 成功后,skill 读 CLI 产出的 `credentials.template.json5`(行数
134
134
  按 §3 验证清单 `ls` / `Read` 校验 CLI 产物存在(除 `testcase.md` 外其他全部,缺任意一项视为整体失败,按 §4 报告):
135
135
 
136
136
  - `testcase.json5`、`credentials.template.json5`(或 `credentials.json5`)、`.ep-stage/contract.json5`、`.ep-stage/inference-trace.json`
137
+ - **凭据硬闸**:若已生成 `credentials.json5`,逐条校验 `url / username / password` 非空(`url` = 登录页地址,运行库只读该字段;仅写 `loginUrl` 不算数)。任一缺失 → 整体失败,回 Step 5 补齐,不进 Step 7。
137
138
 
138
139
  Step 6 只需要确认 CLI 已基于 `testcase.json5` 事实源写出 `testcase.md`。该文件固定是一张审阅表,列为:用例 ID / 生成策略 / 用例标题 / 查询主键 / 前置条件 / 执行步骤 / 执行断言。glue 与 ai 统一在同一张表中,通过“生成策略”列区分。每次重跑都会整体覆盖 `testcase.md`;人审意见只写进 `testcase.json5`(JSON5 `// 注释`),不写 `testcase.md`。
139
140
 
@@ -244,11 +245,11 @@ menu: 一级菜单>二级菜单 <!-- 英文键兼容:裸行 menu / menuPath
244
245
  `<需求名>/credentials.template.json5`(按 code_list.json5 的业务角色事实生成模板) + `~/.ep-stage/projects.index.json5` 需求条目(CLI 追加到 `projects[].requirements[]`):
245
246
 
246
247
  ```json5
247
- // credentials.template.json5
248
+ // credentials.template.json5(url = 登录页地址,运行库必填;拷成 credentials.json5 后必须填非空)
248
249
  [
249
250
  {
250
251
  directUrl: "<请填待测页面直达链接,取 view-source: 后面的页面地址>",
251
- loginUrl: "<请填登录地址>",
252
+ url: "<请填登录地址>",
252
253
  systemName: "<请填系统名称>",
253
254
  role: "业务管理员",
254
255
  username: "<请填账号>",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: glue-run-test
3
3
  description: 使用时机:当用户对某需求要「跑测试 / 验证 / 端到端执行 / 跑胶水测试 / 看报告」或显式触发 `/glue-run-test <testcase.json5路径>` 时使用。
4
- version: 2026-08-20+6cf6d2e
4
+ version: 2026-08-26+38131e2
5
5
  argument-hint: "<testcase.json5绝对/相对路径>"
6
6
  compatibility: 需要由 stage-create 生成的 glue 模式 Playwright 项目 + 已审过的 `testcase.json5` + 同目录 `credentials.json5`。
7
7
  metadata:
@@ -14,11 +14,12 @@ metadata:
14
14
  本 skill 编排 `@epoint-testtech/ep-stage-skill` CLI 与 Agent Runtime。分工固定:
15
15
 
16
16
  1. 用户入口只收 `/glue-run-test <testcase.json5路径>`。
17
- 2. CLI `prepare-tasks` 只做确定性工作:定位项目、补组装 glue 骨架、生成 `.ep-stage/ai-runtime-trace.json5` 任务包。
18
- 3. Agent 读取 trace tasks,使用 playwright-cli 观察和操作真实页面,按 O-D-A-V 产出 `.ep-stage/ai-snippets.json5`。
19
- 4. CLI `run` 只读取 Agent 产出的 resolved snippets,幂等追加到 `AI_APPEND_MARKER` 后并执行完整 spec。
20
- 5. 缺少真实 resolved snippet 时,CLI 只写 `needs_review` trace,不追加占位代码、不执行 Playwright,避免假通过。
21
- 6. 失败时写 `.ep-stage/repair-runs/<round>/repair-report.md` 并回写 trace.repairRounds,等待人审确认修补方向。
17
+ 2. CLI `prepare-tasks` 先做确定性工作:定位项目、补组装干净 glue 骨架,并打包已有 AI 候选。
18
+ 3. skill 先执行原始 glue 骨架,读取真实 `stage-glue-*.json` 判断当前系统是否兼容骨架语义。
19
+ 4. 只有确认语义/组件形态不兼容时,skill 才对同一原 `caseId` `demote` 转入 ODAV;环境故障不转换。
20
+ 5. Agent 读取 demote 后的 trace tasks,必须使用有头 `playwright-cli` 观察和操作真实页面,按 O-D-A-V 产出 `.ep-stage/ai-snippets.json5`。
21
+ 6. CLI `run` 只读取 resolved snippets,幂等追加到 `AI_APPEND_MARKER` 后执行最终 spec;缺少 resolved snippet 时不追加占位代码。
22
+ 7. 失败时写 `.ep-stage/repair-runs/<round>/repair-report.md` 并回写 trace.repairRounds,等待人审确认修补方向。
22
23
 
23
24
  skill 负责:路径解析、必要前置校验、任务清单打印、结果回显。用户视角全中文,不暴露 CLI 名称。
24
25
 
@@ -37,13 +38,13 @@ skill 负责:路径解析、必要前置校验、任务清单打印、结果
37
38
  /glue-run-test /abs/path/.../testcase.json5 --debug # 调试模式 → 跑本地 ep-stage-skill dist
38
39
  ```
39
40
 
40
- > `--debug` flag:正常调用走远程 `npx @epoint-testtech/ep-stage-skill@latest`。开发期想测试未发布的本地代码时传 `--debug`,skill 在 Step 4/Step 6 都改用 `node <repo>/packages/ep-stage-skill/dist/src/cli/index.js`:先跑 `prepare-tasks --testcase ...`,Agent 产出 `ai-snippets.json5` 后再跑 `run --testcase ... --ai-snippets ...`。前提:cwd 在 ep-stage monorepo 内(向上能找到 `pnpm-workspace.yaml`);找不到时直接 exit 1 报错,不静默 fallback 到 npx。
41
+ > `--debug` flag:正常调用走远程 `npx @epoint-testtech/ep-stage-skill@latest`。开发期想测试未发布的本地代码时传 `--debug`,skill 在 Step 4/5/7/9 都改用 `node <repo>/packages/ep-stage-skill/dist/src/cli/index.js`。前提:cwd 在 ep-stage monorepo 内(向上能找到 `pnpm-workspace.yaml`);找不到时直接 exit 1 报错,不静默 fallback 到 npx。
41
42
 
42
43
  skill 把入参 `path.resolve` 绝对化,直接消费 `testcase.json5`。用户心智只保留这一个入口,不要求先显式跑 `spec` 再跑 `run`。
43
44
 
44
- ## 2. Agent 执行剧本(7 步任务清单协议)
45
+ ## 2. Agent 执行剧本(9 步任务清单协议)
45
46
 
46
- **任务清单协议(REQ-UX-01)**:load 后**最先**单行展示技能版本(取本 SKILL.md frontmatter 的 `version` 字段),格式 `技能版本:glue-run-test <version>`;随后**立即**打印初始任务清单(Step 0);每完成一步输出单行 `第 N 步 — <中文名> 已完成,进入第 N+1 步 — <下一中文名>...`;Step 7 输出全勾选终态清单 + 摘要(spec 路径 + trace 路径 + 报告路径)。
47
+ **任务清单协议(REQ-UX-01)**:load 后**最先**单行展示技能版本(取本 SKILL.md frontmatter 的 `version` 字段),格式 `技能版本:glue-run-test <version>`;随后**立即**打印初始任务清单(Step 0);每完成一步输出单行 `第 N 步 — <中文名> 已完成,进入第 N+1 步 — <下一中文名>...`;Step 9 输出全勾选终态清单 + 摘要(spec 路径 + trace 路径 + 报告路径)。
47
48
 
48
49
  ### Step 0 — 打印任务清单
49
50
 
@@ -53,10 +54,12 @@ skill 把入参 `path.resolve` 绝对化,直接消费 `testcase.json5`。用
53
54
  - [ ] 第 1 步 — 解析 testcase.json5 路径并定位测试项目
54
55
  - [ ] 第 2 步 — 校验 testcase.json5 输入
55
56
  - [ ] 第 3 步 — 校验 credentials.json5 凭据
56
- - [ ] 第 4 步 — 调用 prepare-tasks 输出 AI 任务包
57
- - [ ] 第 5 步 — Agent 使用 playwright-cli 完成 O-D-A-V 并写 ai-snippets.json5
58
- - [ ] 第 6 步 — 调用 run CLI 合并 snippet 并执行完整 spec
59
- - [ ] 第 7 步 — 收集 spec、trace 与报告产物并输出摘要
57
+ - [ ] 第 4 步 — 生成并校验 glue 骨架
58
+ - [ ] 第 5 步 — 首次执行 glue 骨架并记录兼容性
59
+ - [ ] 第 6 步 — 将不兼容的原用例转入 ODAV 候选
60
+ - [ ] 第 7 步 — ODAV 候选准备运行任务
61
+ - [ ] 第 8 步 — Agent 使用有头浏览器完成 O-D-A-V 并写 ai-snippets.json5
62
+ - [ ] 第 9 步 — 合并 ODAV snippet、执行并收集报告
60
63
  ```
61
64
 
62
65
  ### Step 1 — 解析 testcase.json5 路径并定位测试项目
@@ -85,9 +88,9 @@ skill 把入参 `path.resolve` 绝对化,直接消费 `testcase.json5`。用
85
88
  2. 现在补:skill 顺序问每条角色的 URL / username / password / systemName(free text),直接写 `<需求名>/credentials.json5`。
86
89
  3. 取消:直接退出,不调 CLI。
87
90
 
88
- ### Step 4 — 调用 prepare-tasks 输出 AI 任务包
91
+ ### Step 4 — 生成并校验 glue 骨架
89
92
 
90
- 固定流程:不 which、不扫 monorepo、不 cd、不喂 stdin。用户入口仍只保留 `/glue-run-test <testcase.json5路径>`,但内部先调用 CLI `prepare-tasks`。
93
+ 固定流程:不 which、不扫 monorepo、不 cd、不喂 stdin。先调用 `prepare-tasks`,让 CLI 在缺少 spec 时生成**初始 glue 骨架**。此步骤不执行浏览器 O-D-A-V,也不把运行态数据写入 testcase 或骨架。
91
94
 
92
95
  正常模式:
93
96
 
@@ -115,13 +118,61 @@ node "$REPO/packages/ep-stage-skill/dist/src/cli/index.js" prepare-tasks \
115
118
  CLI prepare-tasks 行为:
116
119
 
117
120
  1. 解析 `runtimeContext` 或向上查找测试项目;若 `crud.spec.ts` 不存在,先自动补跑 `spec` 生成 glue 骨架。
118
- 2. 构建 AI Runtime Tasks:取 `uncoveredCandidates` `generationStrategy="ai"` 且 `coverageStatus!="blocked"` 的候选;`blocked` 候选不进入后续步骤。
119
- 3. `<caseDir>/.ep-stage/ai-runtime-trace.json5`:`tasks` 就绪,`results` 为空。
120
- 4. 输出 trace 路径、spec 路径、AI task 数量和 blocked 数量。
121
+ 2. 校验 `cases[]` 仍是原始 glue 用例,`uncoveredCandidates[]` 只保留此前已经转入的 AI 候选。
122
+ 3. 构建当前已有 AI 候选的 Runtime Tasks;`blocked` 候选不进入后续步骤。
123
+ 4. `<caseDir>/.ep-stage/ai-runtime-trace.json5`:`tasks` 就绪,`results` 为空。
124
+ 5. 输出 trace 路径、spec 路径、AI task 数量和 blocked 数量。
121
125
 
122
126
  CLI 非 0 退出 → 复述 stderr,不进 Step 5。
123
127
 
124
- ### Step 5 — Agent 使用 playwright-cli 完成 O-D-A-V 并写 ai-snippets.json5
128
+ ### Step 5 — 首次执行 glue 骨架并记录兼容性
129
+
130
+ 首次运行必须先执行 `cases[]` 对应的 glue 骨架。即使 trace 中已有 AI tasks,也先用空的/未 resolved 的 `ai-snippets.json5` 运行 glue;不得先假定 ODAV 能覆盖,也不得用运行时猜测改写初始 testcase。
131
+
132
+ 调试模式:
133
+
134
+ ```bash
135
+ node "$REPO/packages/ep-stage-skill/dist/src/cli/index.js" run \
136
+ --testcase <projectDir>/src/tests/<需求名>/testcase.json5 \
137
+ --ai-snippets <projectDir>/src/tests/<需求名>/.ep-stage/ai-snippets.json5 \
138
+ --headless false
139
+ ```
140
+
141
+ 正常模式将 `node .../index.js` 替换为 `npx -y @epoint-testtech/ep-stage-skill@latest`。`--headless false` 用于让用户能够旁观首次骨架执行;ODAV 探索阶段另行强制使用 `playwright-cli --headed`。
142
+
143
+ 首次执行后读取最新 `glue-report/<14位时间戳>/stage-glue-*.json`,按 `workflowId` / `playwrightTestTitle` 映射回原 `caseId`,记录:
144
+
145
+ - glue 用例是否真实执行、请求是否发出、定位/iframe 是否可用;
146
+ - 查询默认值、尝试值、是否显式点击搜索、搜索前后列表数量及列表列覆盖;
147
+ - `passed`、`needs_review`、`failed` 及其 `reviewReason`。
148
+
149
+ Playwright 测试全绿不等于 glue 语义通过:查询工作流带有搜索证据不足、字段不在列表列、默认值未改变、树节点选择未提交等复核结论时,必须进入 Step 6。
150
+
151
+ ### Step 6 — 将不兼容的原用例转入 ODAV 候选
152
+
153
+ 这是运行态兜底的正式转换门。只处理**同一原始 glue 用例**,不新增第二条查询用例:
154
+
155
+ 1. 对 `stage-glue-*.json` 中 `executionSource: 'glue_code'` 且确认骨架无法表达当前系统语义的 workflow,调用本地/远程 `demote`:
156
+
157
+ ```bash
158
+ npx -y @epoint-testtech/ep-stage-skill@latest demote \
159
+ --testcase <projectDir>/src/tests/<需求名>/testcase.json5 \
160
+ --case-id <原caseId> \
161
+ --reason "glue运行态不兼容:<结构化原因>;见 <stage-glue报告路径>"
162
+ ```
163
+
164
+ 2. `demote` 必须把 `cases[]` 中的原 `caseId` 原位迁移到 `uncoveredCandidates[]`,设置 `generationStrategy: 'ai'`、`coverageStatus: 'gap'`,保留原业务意图、步骤和断言;不得复制出新的 caseId,不得把真实账号、节点名、列表数量或 locator 写入初始 glue 骨架。
165
+ 3. 下列情况进入 ODAV:控件/iframe 形态无法由骨架动作表达;默认值未改变导致搜索证据无效;树节点选择没有提交搜索;查询前后数量不可比较或字段不在列表列,需要运行态寻找可验证动作。ODAV 仍须按查询规则记录证据,无法证明过滤生效时保留 `needs_review`。
166
+ 4. 纯环境问题(网络、登录、凭据、浏览器权限)不应 demote;写 `repair-report.md` 并先修复环境。普通新增/编辑/导出定位失败只有在确认是骨架形态错配时才 demote。
167
+ 5. 没有不兼容 workflow 时,不修改 testcase,跳到 Step 9 收尾;这保证空白机器的初始产物仍是干净 glue 基线。Step 7/8 仅在确有 demote 候选时执行。
168
+
169
+ `demote` 非 0 退出 → 复述 stderr,停止自动转换,不手工编辑 testcase。
170
+
171
+ ### Step 7 — 为 ODAV 候选准备运行任务
172
+
173
+ 对 Step 6 已迁移的候选重新调用 `prepare-tasks`。此时 trace 中的 `tasks[]` 必须出现对应原 `caseId`;若仍为空,停止并报告 testcase/迁移产物不一致,不进入浏览器探索。
174
+
175
+ ### Step 8 — Agent 使用有头浏览器完成 O-D-A-V 并写 ai-snippets.json5
125
176
 
126
177
  读取 `<caseDir>/.ep-stage/ai-runtime-trace.json5` 的 `tasks[]`。若任务数为 0,写一个空结果包:
127
178
 
@@ -137,7 +188,7 @@ CLI 非 0 退出 → 复述 stderr,不进 Step 5。
137
188
  若存在任务,先跑 `which playwright-cli` 校验本机已安装官方 CLI(v0.1.15+ 起支持 coding agent one-shot 子命令 + daemon session 模型)。缺失 → 整包 `needs_review` 后退出。可用则读 `docs/00-memory/dev-rules.md`,再按 `references/playwright-cli-odav.md` 执行:
138
189
 
139
190
  1. 生成一个命名 session:`SESSION="<moduleId>-$(date +%Y%m%d%H%M%S)"`,后续所有子命令都传 `-s=$SESSION`(daemon 保持浏览器 + cookies + localStorage 跨命令)。
140
- 2. 从 `testcase.json5.testAccess.requiredRoles[0]` 取 primary role,从 `credentials.json5` 匹配该角色的 `loginUrl / username / password`。跑 `playwright-cli -s=$SESSION open <loginUrl> --headed`(**必须 `--headed`**,人工旁观 O-D-A-V 过程;不允许无头默认,避免运行态钻探变成无监督黑盒)→ `snapshot` accessibility tree yml 拿 refs `fill <userRef> <username>` / `fill <passRef> <password>` / `click <loginRef>` `snapshot` 验证登录成功。可选 `state-save <caseDir>/.ep-stage/auth.json` 便于跨 session 复用。
191
+ 2. 从 `testcase.json5.testAccess.requiredRoles[0]` 取 primary role,从 `credentials.json5` 匹配该角色的 `url`(= loginUrl)/ `username` / `password`。**登录复用优先**:glue 骨架的登录流程已在 Step 5 首次执行中验证可行时(存在 `<caseDir>/.ep-stage/auth.json` 或骨架已保存的有效认证态),ODAV 阶段直接 `playwright-cli -s=$SESSION state-load <auth.json>` `goto <directUrl>` 验证落地页,**禁止再逐步探索登录**(snapshot ref → fill click 只在复用失败、确认认证态失效时才作为兜底执行)。必须 `--headed`,人工旁观 O-D-A-V 过程;不允许无头默认,避免运行态钻探变成无监督黑盒。兜底登录后 `state-save <caseDir>/.ep-stage/auth.json` 供后续复用。
141
192
  3. `playwright-cli -s=$SESSION goto <contract.base.navigation.directUrl>` 直达列表页 → `snapshot` 观察 iframe 与初始 DOM。
142
193
  4. **初始元素扫描(page-element-scan 内核)**:在列表页加载完成后,用 `playwright-cli run-code` 将 `extract-page-elements-eval.mjs` 函数体注入主 frame 执行,拿到当前页元素清单落袋 `<caseDir>/.ep-stage/elementmap.json`(`{ title, scannedAt, elements[] }` 原始格式,grid 条目保留 `columns`/`rowActions` 供字段→列号映射)。后续 O-D-A-V 推理时 Agent 优先查此 map,snapshot refs 仅用于验证动作已生效。**不写 trace 根级**——`run` 子命令回写 trace 时全量覆盖,Agent 侧写入的自定义字段会被冲掉。
143
194
  ```bash
@@ -157,13 +208,21 @@ CLI 非 0 退出 → 复述 stderr,不进 Step 5。
157
208
  ```
158
209
  - **Verify**:二次 snapshot 或 `eval "<js>"` 验证动作已生效并抽取断言值。
159
210
  **refs 每次 snapshot 后重新编号,禁止跨 snapshot 缓存。**
160
- 6. Agent `dev-rules.md` 把观察 + 动作原料改写为符合本项目规范的 `test()` snippet(`repo*` 前缀、锚点作用域、复用 crud.spec.ts 已声明的 `directListUrl / credentialsPath / primaryRole / crudSlots / exportSlots` 常量,不重复声明)。**test 标题必须带 caseId 前缀**(如 `TC01015 同步窗口管理系统`),与 glue 用例的 `TCxxxxx 标题` 形态对齐,报告按标题回显用例 ID。
161
- 7. 写 `<caseDir>/.ep-stage/ai-snippets.json5`,格式 `{ schemaVersion, testcasePath, generatedAt, results }`;每条 result 的 `evidence` 保留 `source: 'playwright-cli'` + snapshot yml 路径,支撑可观测性 gate。**specSnippet 值必须是合法 JSON5 字符串(单/双引号 + 转义),禁止反引号模板字符串**——JSON5 不支持 `` ` ``,run 解析即崩;建议用脚本 `JSON.stringify` 生成文件而非手写。
162
- 8. 全部 task 完成后跑 `playwright-cli -s=$SESSION close` 释放 session(异常时 `playwright-cli kill-all` 兜底)。
211
+ 6. 对查询类 task,必须执行以下差异化搜索决策(这是 ODAV 保底逻辑,不修改 glue 骨架):
212
+ - 先读取搜索前列表总数/可见行数,并读取查询控件当前值。页面初始值已经参与列表展示,原值不变直接点搜索不能算验证。
213
+ - 先用 `elementmap.json` grid columns 判断查询字段是否出现在列表列中。若字段在列表列中,从当前可见行读取一个真实字段值(优先选择与当前查询值不同的值)作为尝试值;不得用默认值或随机值替代列表中的值。若只有同值可选,则清空后搜索并在证据中说明。
214
+ - 若字段不在列表列中(下钻/隐藏查询字段),先选择或合理猜测一个与页面默认值不同的值;例如默认当前月份的日期控件可以先清空搜索值。先执行搜索,再根据结果判断是否需要复审,不因候选值不是列表实值而提前阻断。
215
+ - 填入/选中尝试值后必须显式点击「搜索/查询」;树节点选择绝不能代替点击搜索。记录默认值、尝试值及其来源(列表实值、控件选项或 ODAV 推断/猜测)。
216
+ - 只有搜索前后总数发生变化,才可将过滤判为已验证。若第一次候选无变化,最多再尝试一个有证据的不同候选;不要使用随机值掩盖无数据问题。
217
+ - 如果总数不可读、尝试值与默认值没有实际区别、搜索前后数据量无变化,或查询字段不在列表列中,结果必须标 `needs_review`,报告写明「需人工复审」、字段是否在列表列、默认值、尝试值及来源、搜索前后数量和原因。字段不在列表列时,即使数量发生变化,也必须保留人工复审标记。
218
+ - 当前月份不是禁用值;只有在它是页面未改变的初始值时,才不能作为有效证据。
219
+ 7. Agent 按 `dev-rules.md` 把观察 + 动作原料改写为符合本项目规范的 `test()` snippet(`repo*` 前缀、锚点作用域、复用 crud.spec.ts 已声明的 `directListUrl / credentialsPath / primaryRole / crudSlots / exportSlots` 常量,不重复声明)。**test 标题必须带 caseId 前缀**(如 `TC01015 同步窗口管理系统`),与 glue 用例的 `TCxxxxx 标题` 形态对齐,报告按标题回显用例 ID。
220
+ 8. 写 `<caseDir>/.ep-stage/ai-snippets.json5`,格式 `{ schemaVersion, testcasePath, generatedAt, results }`;每条 result 的 `evidence` 保留 `source: 'playwright-cli'` + snapshot yml 路径,支撑可观测性 gate。查询 task 的 `reviewReason` 必须同时写入上述差异化证据;若需人工复审,result 使用 `status: 'needs_review'`,不得伪造 resolved。**specSnippet 值必须是合法 JSON5 字符串(单/双引号 + 转义),禁止反引号模板字符串**——JSON5 不支持 `` ` ``,run 解析即崩;建议用脚本 `JSON.stringify` 生成文件而非手写。
221
+ 9. 全部 task 完成后跑 `playwright-cli -s=$SESSION close` 释放 session(异常时 `playwright-cli kill-all` 兜底)。
163
222
 
164
223
  宿主 Agent 无 `playwright-cli`、目标系统网络不可达、testcase 信息不足或断言无法确认时,不强造 snippet;对应 result 标 `needs_review`,并在 observation/evidence 中写明原因。
165
224
 
166
- ### Step 6调用 run CLI 合并 snippet 并执行完整 spec
225
+ ### Step 9合并 ODAV snippet、执行最终 spec
167
226
 
168
227
  正常模式:
169
228
 
@@ -186,19 +245,19 @@ node "$REPO/packages/ep-stage-skill/dist/src/cli/index.js" run \
186
245
  CLI run 行为:
187
246
 
188
247
  1. 读取 ai-snippets.json5;只合并 `status="resolved"` 且 `specSnippet` 非空、caseId 属于当前 tasks 的结果。
189
- 2. 若存在 AI tasks 但缺少完整 resolved snippet,写 trace `needs_review` 后停止,不追加占位代码、不执行 Playwright。
248
+ 2. 缺少 resolved snippet AI task trace `needs_review`,不追加占位代码;默认继续执行 glue 与已 resolved 用例并回显 `needsReviewCount`(Step 5 的 glue 基线执行正是依赖这个部分执行语义);只在显式传 `--strict-ai true` 时,任一 AI task 未决才整体短路。
190
249
  3. 若 snippets 完整,定位 `AI_APPEND_MARKER` 截断旧追加段,按任务顺序追加 snippets。
191
250
  4. 从 `projectDir` 跑 `npx playwright test <specPath>`,`headless=false` 时带 `--headed`。
192
- 5. 失败时归类并写 `.ep-stage/repair-runs/<round>/repair-report.md`,同时回写 `trace.repairRounds`。
251
+ 5. 失败时归类并写 `.ep-stage/repair-runs/<round>/repair-report.md`,同时回写 `trace.repairRounds`。ODAV 已接管的用例失败时不回退修改 glue 骨架;等待人审确认修补方向后重跑 ODAV。
193
252
 
194
- CLI 非 0 退出 → 复述 stderr,不进 Step 7。
253
+ CLI 非 0 退出 → 复述 stderr,不进入收尾。
195
254
 
196
- ### Step 7 — 收集 spec、trace 与报告产物并输出摘要
255
+ #### Step 9 收尾校验 — 收集 spec、trace 与报告产物并输出摘要
197
256
 
198
257
  用 `ls` / `Read` 校验 §3 验证清单。成功信号:
199
258
 
200
259
  - `crud.spec.ts` 已存在;若原先缺失,说明 prepare-tasks 已自动补组装。
201
- - `ai-runtime-trace.json5` 已落盘且含 tasks + results;若 results `needs_review`,按原因提示继续 Agent O-D-A-V
260
+ - `ai-runtime-trace.json5` 已落盘且含 tasks + results;若 glue 首次执行报告发现语义不兼容,必须能看到原 `caseId` 已迁移到 `uncoveredCandidates`,随后 trace 才会出现对应 ODAV task
202
261
  - `ai-snippets.json5` 已落盘;resolved 结果已合并到 spec,needs_review 结果不会合并。
203
262
  - 报告目录已创建。
204
263
  - 成功路径不落 repair report;若失败,`.ep-stage/repair-runs/<round>/repair-report.md` 存在,按 §4 引导人审确认修补方向。
@@ -212,7 +271,7 @@ CLI 非 0 退出 → 复述 stderr,不进 Step 7。
212
271
  | `<projectDir>/src/tests/<需求名>/testcase.json5` | 必须存在 + `schemaVersion` 合法 |
213
272
  | `<projectDir>/src/tests/<需求名>/credentials.json5` | 必须存在 + 数组 ≥ 1 条 + 必填字段非空 |
214
273
  | `<projectDir>/src/tests/<需求名>/.ep-stage/contract.json5` | 由 testcase 阶段产,run 阶段只读不写 |
215
- | `<projectDir>/src/tests/<需求名>/.ep-stage/ai-runtime-trace.json5` | prepare-tasks 先写 tasks;run 回写 results / repairRounds |
274
+ | `<projectDir>/src/tests/<需求名>/.ep-stage/ai-runtime-trace.json5` | prepare-tasks 写当前 ODAV tasks;run 回写 results / repairRounds;首次 glue 执行没有可转候选时 tasks 可为空 |
216
275
  | `<projectDir>/src/tests/<需求名>/.ep-stage/elementmap.json` | Agent O-D-A-V 落的页面控件定位清单(含 grid columns);run 不触碰 |
217
276
  | `<projectDir>/src/tests/<需求名>/.ep-stage/repair-runs/<round>/repair-report.md` | 失败时才产;含失败分类与摘要,待人审确认 |
218
277
  | `<projectDir>/glue-report/<run-timestamp>/` | run 子命令产;执行账本(`index.html` glue 风格综合报告(全部用例)+ `playwright-results.json` + `run-output.log` 完整执行输出 + `run-info.json`) |
@@ -228,12 +287,14 @@ CLI 非 0 退出 → 复述 stderr,不进 Step 7。
228
287
  | 引导 C(缺凭据) | AskUserQuestion 三选一:缓存复用 / 现在补 / 取消 |
229
288
  | prepare-tasks / run 子命令 exit ≠ 0 | 复述 stderr;若缺 spec,也可能是 prepare-tasks 自动补跑 spec 失败 |
230
289
  | glue cases 为空 | 阻断 prepare-tasks 内部 spec 组装;提示用户回 `/glue-generate-testcase` 补齐 |
231
- | Playwright 执行失败 | 回显 `repairReportPath` 与失败分类;建议用户确认修补方向后重跑 `/glue-run-test <testcase.json5路径>`,不静默改 testcase |
290
+ | glue 首次执行出现语义不兼容 | 读取最新 `stage-glue-*.json`,对原 `caseId` 执行 `demote`,重跑 `prepare-tasks`,随后必须进入有头浏览器 ODAV;不得新建第二条用例 |
291
+ | glue 首次执行是环境失败 | 回显失败分类与 `repairReportPath`,先修复网络/登录/权限等环境问题,不得 demote |
292
+ | ODAV Playwright 执行失败 | 回显 `repairReportPath` 与失败分类,等待人审确认修补方向后重跑 ODAV,不修改 glue 骨架 |
232
293
  | 用户中途取消 | AskUserQuestion 阶段说「算了/取消」立即终止;CLI 启动后等其退出再复述 |
233
294
 
234
295
  ## 5. 完成提示
235
296
 
236
- Step 7 全部通过后,按以下中文格式呈现:
297
+ Step 9 收尾后,按以下中文格式呈现:
237
298
 
238
299
  > 胶水测试执行完成
239
300
  >
@@ -246,7 +307,7 @@ Step 7 全部通过后,按以下中文格式呈现:
246
307
  >
247
308
  > 下一步:① 调整 `testcase.json5` / `contract.json5` 后重跑 `/glue-run-test <testcase.json5路径>`;② 失败时查看 repair-report.md 确认修补方向后再重跑。
248
309
 
249
- 失败时不要发完成提示:Playwright 失败已落 repair-report.md,按 §4 引导人审确认修补方向,不允许混合"执行完成"字样。
310
+ 若发生 glue → ODAV 转换,应在完成提示中同时列出:原 glue 首次报告、demote 的原 `caseId`、ODAV 的有头探索证据和最终报告。失败时不要发完成提示:Playwright 失败已落 repair-report.md,按 §4 引导人审确认修补方向,不允许混合"执行完成"字样。
250
311
 
251
312
  ## 6. 产物生命周期
252
313
 
@@ -289,7 +350,9 @@ Step 7 全部通过后,按以下中文格式呈现:
289
350
 
290
351
  - 钻探前置:本 skill 不再实现 contract 提取、coverage 分析、`uncoveredCandidates` 推断;这些在 `/glue-generate-testcase` 完成。
291
352
  - 当前用户入口只保留 `/glue-run-test <testcase.json5路径>`;不要要求用户先显式跑 `spec`。
292
- - Agent AI 用例执行受控运行态推理并写 ai-snippets.json5;run 子命令只合并 resolved snippet 后执行完整 spec;失败时先落 repair-report.md 等待确认,不静默改变 testcase 意图。
353
+ - Agent 必须先执行原始 glue 骨架,再依据真实报告判断兼容性;只有确认骨架无法表达当前系统语义时,才用 `demote` 将同一 `caseId` 转入 ODAV。不得在初始生成阶段凭运行记忆直接生成 ODAV 代码。纯环境问题(网络、登录、凭据)修复后重跑骨架,不走 demote。
354
+ - ODAV 阶段登录态优先复用(state-load 已保存的 auth.json / 骨架已验证的认证缓存),复用失败才逐步账密登录;禁止把登录探索当作每条 task 的固定前奏。
355
+ - ODAV task 必须由有头 `playwright-cli` O-D-A-V 产出 ai-snippets.json5;run 子命令只合并 resolved snippet 后执行最终 spec;失败时先落 repair-report.md 等待确认,不修改 glue 骨架。
293
356
  - `coverageStatus="blocked"` 的候选不进入 AI Runtime Task、不写 trace、不进 spec 追加段。
294
357
  - spec / run 都不得对 contract 缺失槽位二次猜测。
295
358
  - 用户视角始终全中文;业务断言、selector、iframe 关键字、按钮文案均由骨架 + `contract.json5` 的 `scenario.skeletonSlots` 决策,skill 不发明。
@@ -2,22 +2,28 @@
2
2
 
3
3
  glue-run-test 对 `generationStrategy=ai` 的用例采用受控运行态推理。
4
4
 
5
- 状态机:
5
+ 状态机(先 glue、后 ODAV):
6
6
 
7
7
  ```text
8
- prepare_tasks_cli
9
- -> agent_infer_ai_snippets
10
- -> compose_full_spec_cli
11
- -> run_full_spec
12
- -> classify_result
13
- -> passed: final_report
14
- -> failed: write_repair_report
8
+ prepare_glue_spec
9
+ -> run_glue_baseline
10
+ -> classify_compatibility
11
+ -> compatible: final_report
12
+ -> semantic_mismatch: demote_same_case_id
13
+ -> prepare_ai_tasks
14
+ -> agent_infer_ai_snippets (headed)
15
+ -> compose_full_spec_cli
16
+ -> run_odav_spec
17
+ -> classify_result
18
+ -> passed: final_report
19
+ -> failed: write_repair_report
20
+ -> environment_failure: write_repair_report
15
21
  -> wait_human_direction
16
22
  -> repair_spec
17
23
  -> rerun
18
24
  ```
19
25
 
20
- Agent 可以读取 trace tasks,并使用 playwright-cli 观察页面、iframe、弹窗、提示和网络反馈;CLI 不做业务推理。Agent 不能新增测试范围、反刷 code_list.json5、静默改 testcase.json5 或绕开 docs/00-memory/dev-rules.md
26
+ Agent 可以读取 trace tasks,并使用有头 `playwright-cli` 观察页面、iframe、弹窗、提示和网络反馈;CLI 不做业务推理。Agent 不能新增测试范围、反刷 code_list.json5、静默改 testcase.json5 或绕开 docs/00-memory/dev-rules.md。首次 glue 运行产生的兼容性报告是进入 ODAV 的唯一依据;没有语义不兼容证据时保持干净 glue 基线。
21
27
 
22
28
  失败后第一版只落:
23
29
 
@@ -8,8 +8,9 @@
8
8
  | --- | --- | --- |
9
9
  | `testcase` | `glue-generate-testcase` skill 包装 | 上游钻探 + contract 提取 + coverage 分析 + testcase v1-draft 生成 + credentials.template 生成 + code_list 软链 |
10
10
  | `spec` | `glue-run-test` skill 包装(**只生成不执行**) | 读 testcase + contract → 组装胶水骨架 `crud.spec.ts`(仅覆盖 cases[] 胶水部分) |
11
- | `prepare-tasks` | `glue-run-test` skill 包装 | 读 testcase(spec 缺失则自动组装)→ ai 候选构建 runtime task → 写 ai-runtime-trace.json5 |
12
- | `run` | `glue-run-test` skill 包装 | Agent 产出的 ai-snippets.json5 合并 resolved snippet → 执行完整 spec → 失败归类写 repair report |
11
+ | `prepare-tasks` | `glue-run-test` skill 包装 | 读 testcase(spec 缺失则自动组装)→ 为已有 ai 候选构建 runtime task → 写 ai-runtime-trace.json5 |
12
+ | `run`(首次) | `glue-run-test` skill 包装 | 先执行原始 glue cases;报告语义不兼容时由 skill 对原 caseId `demote`,不在生成阶段猜测 |
13
+ | `run`(ODAV) | `glue-run-test` skill 包装 | 读 Agent 产出的 ai-snippets.json5 → 合并 resolved snippet → 执行最终 spec → 失败归类写 repair report |
13
14
 
14
15
  > **contract 提取已内嵌**到 `testcase` 子命令(REQ-CLI-02),不暴露为独立 CLI 命令。开发期可用 `pnpm generate:crud-contract`(路由到 `src/cli/dev/extract-contract.ts`),仅作调试入口,**不进 SKILL.md**。
15
16
 
@@ -49,6 +50,12 @@ npx -y @epoint-testtech/ep-stage-skill@latest spec \
49
50
  - 仅覆盖 `cases[]` 胶水部分;`uncoveredCandidates` 留给 Agent Runtime 产出 snippets,再由 `run` 子命令追加
50
51
  - 避免内联 Playwright 操作流程
51
52
 
53
+ ## 首次 glue 基线与兼容性门
54
+
55
+ `prepare-tasks` 只负责补齐/校验 glue spec 和打包已有 AI 候选;它不会因为 `uncoveredCandidates` 为空而自行打开浏览器。skill 必须先调用 `run --headless false` 执行 `cases[]`,读取最新 `glue-report/<14位时间戳>/stage-glue-*.json`。
56
+
57
+ 查询工作流出现默认值未改变、搜索未显式提交、树节点选择未提交、搜索前后数量不可证、查询字段不在列表列等语义结论时,按原 `caseId` 调用 `demote`,把该用例从 `cases[]` 迁移到 `uncoveredCandidates[]`。网络、凭据、权限和浏览器启动失败属于环境故障,不得 demote。
58
+
52
59
  ## 准备 AI 任务(Prepare Tasks)
53
60
 
54
61
  ```bash
@@ -64,7 +71,7 @@ prepare-tasks 内部步骤:
64
71
 
65
72
  ## Agent 推理(Agent O-D-A-V)
66
73
 
67
- Agent 读取 `.ep-stage/ai-runtime-trace.json5`,使用 playwright-cli 观察和操作真实页面,产出 `.ep-stage/ai-snippets.json5`。详见 [playwright-cli-odav.md](./playwright-cli-odav.md)。
74
+ Agent 读取 demote 后重新生成的 `.ep-stage/ai-runtime-trace.json5`,必须使用 `playwright-cli ... open <loginUrl> --headed` 观察页面、iframe、弹窗、提示和网络反馈,产出 `.ep-stage/ai-snippets.json5`。详见 [playwright-cli-odav.md](./playwright-cli-odav.md)。没有 demote 候选时不执行 ODAV
68
75
 
69
76
  ## 执行 + AI snippet 合并(Run + AI Snippet Append)
70
77
 
@@ -42,3 +42,14 @@ recommendedAction: run-ai-runtime | supplement-code-list | block
42
42
  - 不得在缺少 resolved `ai-snippets.json5` 时追加占位 snippet。
43
43
  - 不得通过修改骨架来让一个 gap 假通过。
44
44
  - 修补失败时先写 `repair-report.md` 等待人工确认,不静默削弱断言或改变 testcase 意图。
45
+
46
+ ## 查询类 ODAV 保底
47
+
48
+ 查询首次仍保留在原 glue case;必须先执行一次 glue 骨架。骨架运行报告确认语义不兼容(例如默认值未改变、未显式提交查询、树节点选择未提交、组件/iframe 形态无法表达)后,由流程自动对同一 `caseId` 调用 `demote`,移入 `uncoveredCandidates`,再进入有头浏览器 ODAV。纯网络、凭据、权限失败不触发 demote,先走 repair report。
49
+
50
+ ODAV 接管查询时必须先观察列表状态:
51
+
52
+ - 读取当前列表总数和查询控件当前值。初始值已经用于渲染列表,原值不变提交不构成搜索证据。
53
+ - 先用 `elementmap.json` 的 grid columns 判断字段是否在列表列中:在列表列中时,从当前可见行读取一个真实字段值(优先与当前查询值不同);不在列表列中时,选择或合理猜测一个不同于默认值的日期、下拉选项或树节点值,允许默认当前月份先清空后搜索。不得因候选值非列表实值而提前阻断。
54
+ - 填入/选中后永远显式点击搜索按钮,再比较搜索前后总数。搜索前后无变化、总数不可读或尝试值未实际改变时,结果写 `needs_review`;字段不在列表列时即使数量变化也必须复审。记录字段列覆盖情况、默认值、尝试值及来源、前后数量和「需人工复审」原因。
55
+ - 报告来源应标为 Agent/ODAV 接管,并保留原 glue caseId,避免生成第二条独立查询用例。
@@ -30,7 +30,18 @@
30
30
 
31
31
  ## 执行剧本
32
32
 
33
- ### Step 1 — 登录
33
+ ### Step 1 — 登录(复用优先)
34
+
35
+ **复用优先**:glue 骨架登录已验证可行时(存在 `<caseDir>/.ep-stage/auth.json` 或骨架已保存的有效认证态),直接复用,禁止逐步探索登录:
36
+
37
+ ```bash
38
+ SESSION="<moduleId>-$(date +%Y%m%d%H%M%S)"
39
+ playwright-cli -s="$SESSION" state-load <caseDir>/.ep-stage/auth.json
40
+ playwright-cli -s="$SESSION" goto <directUrl>
41
+ playwright-cli -s="$SESSION" snapshot # 验证落在列表页(未被弹回登录页)即复用成功
42
+ ```
43
+
44
+ 只有复用失败(被弹回登录页 / 无可用认证态文件)时才走逐步账密登录兜底:
34
45
 
35
46
  ```bash
36
47
  SESSION="<moduleId>-$(date +%Y%m%d%H%M%S)"
@@ -41,7 +52,7 @@ playwright-cli -s="$SESSION" fill e12 "<username>"
41
52
  playwright-cli -s="$SESSION" fill e13 "<password>"
42
53
  playwright-cli -s="$SESSION" click e15
43
54
  playwright-cli -s="$SESSION" snapshot # 验证登录成功(URL 或首页 DOM 特征)
44
- playwright-cli -s="$SESSION" state-save <caseDir>/.ep-stage/auth.json # 可选:状态保存
55
+ playwright-cli -s="$SESSION" state-save <caseDir>/.ep-stage/auth.json # 兜底登录后必须落袋,供后续复用
45
56
  ```
46
57
 
47
58
  ### Step 2 — 直达列表页
@@ -0,0 +1,75 @@
1
+ /**
2
+ * calibrate 子命令:运行时校准回路(A 支柱)。
3
+ *
4
+ * 输入 page-element-scan 产出的 elementmap.json(运行时真实控件形态),按确定性规则
5
+ * 改写 contract.json5 的组件类型与定位符槽位,使静态装配与运行时实据对齐。
6
+ *
7
+ * 契约写入纪律(双写入者):contract 只允许 assembler(静态事实)与本 calibrator
8
+ * (运行时实据)两个写入者,均机器执行 + 账本落盘(calibration-report.json)+
9
+ * 过同一 validateContract 门禁;Agent 不手编 contract。
10
+ *
11
+ * 校准规则表(高置信自动改,低置信落 unresolvedSlots 人审):
12
+ * - R1-R4 查询字段 label 命中且 controlType 映射为白名单类型 → 改 component + 重建 slot;
13
+ * - R5 label 命中但 controlType 未识别 → 不改契约,unresolvedSlots += unsupported_query_component;
14
+ * - R6 searchFields label 在 elementmap 未命中 → unresolvedSlots += query_field_not_found;
15
+ * - R7 导出按钮定位符与 elementmap 实据不一致 → 用实据覆盖 exportButton;
16
+ * - R8 elementmap 无「查询/搜索」按钮 → unresolvedSlots += search_submit_unverified;
17
+ * - R9 elementmap 存在导出面板证据(待选列/已选列)→ 注入 exportContainer 语义锚点。
18
+ *
19
+ * 默认 dry-run(只打印变更计划);--write 才落盘并级联重生成 spec / 重渲染 testcase.md。
20
+ * 组件类别变化导致用例文案变化时,该用例 reviewStatus 拨回 needs_review(机器改语义必人审)。
21
+ */
22
+ import type { UnresolvedSlotRecord } from '../contracts/glue-contract-v1.js';
23
+ /**
24
+ * calibrate 子命令参数。
25
+ */
26
+ export type CalibrateArgs = {
27
+ /** testcase.json5 路径 */
28
+ testcase: string;
29
+ /** elementmap.json 路径(缺省 <caseDir>/.ep-stage/elementmap.json) */
30
+ elementmap?: string;
31
+ /** true 时落盘并级联重生成;缺省 dry-run 只打印变更计划 */
32
+ write: boolean;
33
+ };
34
+ /** 校准变更记录。 */
35
+ export type CalibrationChange = {
36
+ slotPath: string;
37
+ from: string;
38
+ to: string;
39
+ rule: string;
40
+ evidence: {
41
+ label?: string;
42
+ locator?: string;
43
+ controlType?: string;
44
+ };
45
+ };
46
+ /**
47
+ * calibrate 子命令产物。
48
+ */
49
+ export type CalibrateResult = {
50
+ reportPath: string;
51
+ changes: CalibrationChange[];
52
+ unresolvedAdded: UnresolvedSlotRecord[];
53
+ /** 因组件变化被拨回 needs_review 的用例 ID 清单 */
54
+ casesPatched: string[];
55
+ /** 是否已落盘(false = dry-run) */
56
+ written: boolean;
57
+ /** 是否已级联重生成 spec(用例拨回 needs_review 时跳过,待人工确认后由 prepare-tasks/run 补齐) */
58
+ specRegenerated: boolean;
59
+ };
60
+ /**
61
+ * 解析 calibrate 子命令参数。
62
+ *
63
+ * @param argv - 已剥离子命令名的命令行参数。
64
+ * @returns CalibrateArgs。
65
+ */
66
+ export declare function parseCalibrateArgs(argv: string[]): CalibrateArgs;
67
+ /**
68
+ * 执行运行时校准。
69
+ *
70
+ * @param args - calibrate 参数。
71
+ * @returns CalibrateResult。
72
+ * @throws elementmap 缺失 / 校验门禁失败(不落盘)时抛错。
73
+ */
74
+ export declare function runCalibrate(args: CalibrateArgs): CalibrateResult;
75
+ //# sourceMappingURL=calibrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calibrate.d.ts","sourceRoot":"","sources":["../../../src/cli/calibrate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAUH,OAAO,KAAK,EAA0B,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAoBrG;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,wBAAwB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,cAAc;AACd,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACtE,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,eAAe,EAAE,oBAAoB,EAAE,CAAC;IACxC,sCAAsC;IACtC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,6BAA6B;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,wEAAwE;IACxE,eAAe,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CAmBhE;AAoED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,eAAe,CA8NjE"}