@tea-agent/loop-agent 0.19.0 → 0.20.1-beta.0

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 (31) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/application/dag/generate-task-dag.js +12 -1
  3. package/dist/executors/shell-executor.js +189 -2
  4. package/dist/worker/observe/spec-evidence.js +33 -0
  5. package/dist/worker/observe/static/views/dag-inspector.js +67 -4
  6. package/dist/workflows/dag/backend-test-markdown-workflow.js +163 -41
  7. package/dist/workflows/dag/backend-test-result-contract.js +30 -7
  8. package/dist/workflows/dag/frontend-prewrite-gate.js +172 -0
  9. package/dist/workflows/dag/frontend-project-capability.js +6 -2
  10. package/dist/workflows/dag/frontend-repair.js +7 -1
  11. package/dist/workflows/dag/frontend-review-context.js +43 -0
  12. package/dist/workflows/dag/frontend-verification-trace.js +34 -15
  13. package/dist/workflows/dag/governance-profile.js +14 -6
  14. package/dist/workflows/dag/init-hybrid.js +144 -399
  15. package/dist/workflows/dag/types.js +33 -0
  16. package/dist/workflows/dag/validate.js +22 -1
  17. package/docs/README.md +1 -0
  18. package/docs/templates/agent-dag.schema.json +40 -0
  19. package/docs/templates/backend-test-dag.generate-pytest.prompt.md +23 -192
  20. package/docs/templates/backend-test-dag.json +8 -8
  21. package/docs/templates/backend-test-dag.review-cases.prompt.md +22 -75
  22. package/package.json +1 -1
  23. package/skills/frontend-design-review/SKILL.md +5 -3
  24. package/skills/frontend-design-review/references/review-checklist.md +3 -2
  25. package/skills/frontend-implementation/references/design-spec.md +16 -8
  26. package/skills/frontend-implementation/references/node-contracts.md +6 -8
  27. package/skills/frontend-review/SKILL.md +12 -9
  28. package/skills/frontend-review/references/review-findings.md +5 -1
  29. package/skills/frontend-verification/SKILL.md +5 -3
  30. package/skills/frontend-verification/references/verification-checklist.md +3 -2
  31. package/skills/loop-agent/references/hybrid-dag.md +2 -2
@@ -113,6 +113,36 @@ export const dagJsonArtifactGateSchema = z.object({
113
113
  outputDir: z.string().regex(/^[a-z0-9][a-z0-9._-]*$/),
114
114
  junitRelativePath: z.string().min(1).optional(),
115
115
  });
116
+ const dagFrontendNodeIdSchema = z
117
+ .string()
118
+ .regex(/^[a-z][a-z0-9-]*$/, "frontend node id must be kebab-case");
119
+ export const dagFrontendPrewriteGateSchema = z.object({
120
+ schemaVersion: z.literal(1),
121
+ planFromNodeId: dagFrontendNodeIdSchema,
122
+ planFallbackFromNodeIds: z.array(dagFrontendNodeIdSchema).default([]),
123
+ reviewFromNodeId: dagFrontendNodeIdSchema,
124
+ reviewFallbackFromNodeIds: z.array(dagFrontendNodeIdSchema).default([]),
125
+ requiredRequirementIds: z.array(z.string().regex(/^(?:REQ|BR|AC)-[A-Z0-9]+(?:-[A-Z0-9]+)*$/)).default([]),
126
+ allowedMockStrategies: z.array(z.enum(["native", "browser-intercept", "request-adapter", "not-needed"])).min(1),
127
+ artifactName: z.string().regex(/^[a-z0-9][a-z0-9._-]*\.json$/),
128
+ outputDir: z.string().regex(/^[a-z0-9][a-z0-9._-]*$/),
129
+ openspecCandidatePaths: z
130
+ .array(z.string().regex(/^openspec\/.+/, "openspec candidate must be repo-relative"))
131
+ .default([]),
132
+ });
133
+ export const dagFrontendVerificationBundleSchema = z.object({
134
+ schemaVersion: z.literal(1),
135
+ mockCommands: z.array(z.string()).default([]),
136
+ staticCommands: z.array(z.string()).min(1),
137
+ behaviorCommands: z.array(z.string()).min(1),
138
+ mockEvidence: dagShellVerifyEvidenceSchema.optional(),
139
+ staticEvidence: dagShellVerifyEvidenceSchema,
140
+ behaviorEvidence: dagShellVerifyEvidenceSchema,
141
+ mode: z.enum(["initial", "repair"]),
142
+ });
143
+ export const dagFrontendReviewContextSchema = z.object({
144
+ schemaVersion: z.literal(1),
145
+ });
116
146
  export const ENV_VAR_NAME_PATTERN = /^[A-Z_][A-Z0-9_]*$/;
117
147
  export const dagVersionSchema = z
118
148
  .union([z.literal(1), z.literal(2), z.literal(3), z.literal(4)])
@@ -191,6 +221,9 @@ export const dagShellConfigSchema = z.object({
191
221
  }).strict().optional(),
192
222
  requirementCoverageGate: dagRequirementCoverageGateSchema.optional(),
193
223
  jsonArtifactGate: dagJsonArtifactGateSchema.optional(),
224
+ frontendPrewriteGate: dagFrontendPrewriteGateSchema.optional(),
225
+ frontendVerificationBundle: dagFrontendVerificationBundleSchema.optional(),
226
+ frontendReviewContext: dagFrontendReviewContextSchema.optional(),
194
227
  backendTestPipeline: dagBackendTestPipelineSchema.optional(),
195
228
  verifyEvidence: dagShellVerifyEvidenceSchema.optional(),
196
229
  repairArtifactGate: dagRepairArtifactGateSchema.optional(),
@@ -456,7 +456,12 @@ function validateShellTaskConfig(task, spec, issues) {
456
456
  return;
457
457
  }
458
458
  const commands = resolveShellCommands(shell);
459
- if (commands.length === 0 && !shell.jsonArtifactGate && !shell.backendTestPipeline) {
459
+ if (commands.length === 0 &&
460
+ !shell.jsonArtifactGate &&
461
+ !shell.backendTestPipeline &&
462
+ !shell.frontendPrewriteGate &&
463
+ !shell.frontendVerificationBundle &&
464
+ !shell.frontendReviewContext) {
460
465
  issues.push({
461
466
  type: "missing-shell-commands",
462
467
  message: `shell task ${task.id} requires shell.preset, shell.verdictGate, shell.jsonArtifactGate, shell.backendTestPipeline, and/or non-empty shell.commands`,
@@ -517,6 +522,22 @@ function validateShellTaskConfig(task, spec, issues) {
517
522
  }
518
523
  }
519
524
  }
525
+ if (shell.frontendPrewriteGate) {
526
+ const sourceNodeIds = [
527
+ shell.frontendPrewriteGate.planFromNodeId,
528
+ ...shell.frontendPrewriteGate.planFallbackFromNodeIds,
529
+ shell.frontendPrewriteGate.reviewFromNodeId,
530
+ ...shell.frontendPrewriteGate.reviewFallbackFromNodeIds,
531
+ ];
532
+ for (const sourceNodeId of new Set(sourceNodeIds)) {
533
+ if (!task.depends_on.includes(sourceNodeId)) {
534
+ issues.push({
535
+ type: "missing-dependency",
536
+ message: `shell task ${task.id} frontendPrewriteGate source ${sourceNodeId} must be a direct dependency`,
537
+ });
538
+ }
539
+ }
540
+ }
520
541
  validateRepairArtifactGateConfig(task, spec, issues);
521
542
  validateShellVerdictGateGovernance(task, commands, issues);
522
543
  }
package/docs/README.md CHANGED
@@ -75,6 +75,7 @@
75
75
 
76
76
  完整 completed 列表与主题速览见 `exec-plans/completed/README.md`。近期高频归档:
77
77
 
78
+ - `exec-plans/completed/2026-07-23-backend-test-human-readable-artifacts.md` — 中文 README/用例卡片、class-based pytest traceability 与逐条 self-contained HTML 报告;真实 `my-webapp` Campaign Round 04 8/8、16 passed
78
79
  - `exec-plans/completed/2026-07-22-backend-markdown-gate-fix.md` — backend-test Markdown gate、traceability、中文生成与真实 Campaign 收口
79
80
  - `exec-plans/completed/2026-07-22-backend-test-markdown-first-8-node.md` — backend-test Markdown-first 8 节点
80
81
  - `exec-plans/completed/2026-07-22-backend-test-report-first-flow.md` — backend-test 报告优先 12 节点
@@ -303,6 +303,43 @@
303
303
  "junitRelativePath": { "type": "string", "minLength": 1 }
304
304
  }
305
305
  },
306
+ "frontendPrewriteGate": {
307
+ "type": "object",
308
+ "additionalProperties": false,
309
+ "required": ["schemaVersion", "planFromNodeId", "reviewFromNodeId", "allowedMockStrategies", "artifactName", "outputDir"],
310
+ "properties": {
311
+ "schemaVersion": { "const": 1 },
312
+ "planFromNodeId": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
313
+ "planFallbackFromNodeIds": { "type": "array", "items": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" } },
314
+ "reviewFromNodeId": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
315
+ "reviewFallbackFromNodeIds": { "type": "array", "items": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" } },
316
+ "requiredRequirementIds": { "type": "array", "items": { "type": "string", "pattern": "^(?:REQ|BR|AC)-[A-Z0-9]+(?:-[A-Z0-9]+)*$" } },
317
+ "allowedMockStrategies": { "type": "array", "minItems": 1, "items": { "enum": ["native", "browser-intercept", "request-adapter", "not-needed"] } },
318
+ "artifactName": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*\\.json$" },
319
+ "outputDir": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" }
320
+ }
321
+ },
322
+ "frontendVerificationBundle": {
323
+ "type": "object",
324
+ "additionalProperties": false,
325
+ "required": ["schemaVersion", "staticCommands", "behaviorCommands", "staticEvidence", "behaviorEvidence", "mode"],
326
+ "properties": {
327
+ "schemaVersion": { "const": 1 },
328
+ "mockCommands": { "type": "array", "items": { "type": "string" } },
329
+ "staticCommands": { "type": "array", "minItems": 1, "items": { "type": "string" } },
330
+ "behaviorCommands": { "type": "array", "minItems": 1, "items": { "type": "string" } },
331
+ "mockEvidence": { "$ref": "#/$defs/shellVerifyEvidence" },
332
+ "staticEvidence": { "$ref": "#/$defs/shellVerifyEvidence" },
333
+ "behaviorEvidence": { "$ref": "#/$defs/shellVerifyEvidence" },
334
+ "mode": { "enum": ["initial", "repair"] }
335
+ }
336
+ },
337
+ "frontendReviewContext": {
338
+ "type": "object",
339
+ "additionalProperties": false,
340
+ "required": ["schemaVersion"],
341
+ "properties": { "schemaVersion": { "const": 1 } }
342
+ },
306
343
  "backendTestPipeline": {
307
344
  "enum": ["contracts", "semantic-initial", "execute-parse-initial", "classification-result-context"]
308
345
  },
@@ -324,6 +361,9 @@
324
361
  { "required": ["verdictGate"] },
325
362
  { "required": ["requirementCoverageGate"] },
326
363
  { "required": ["jsonArtifactGate"] },
364
+ { "required": ["frontendPrewriteGate"] },
365
+ { "required": ["frontendVerificationBundle"] },
366
+ { "required": ["frontendReviewContext"] },
327
367
  { "required": ["backendTestPipeline"] }
328
368
  ]
329
369
  },
@@ -2,205 +2,36 @@
2
2
 
3
3
  ## Purpose
4
4
 
5
- Use this prompt for a **pytest code generation** node: `executor: "pi"`, `role: "implementer"`, `toolProfile: "write"`, `writePolicy: "exclusive"`. The implementer converts validated backend functional test cases into pytest automation code with 1:1 traceability. The independent case review is advisory evidence and does not authorize this writer.
5
+ `generate-backend-pytest-pi` 使用。该节点是 `executor: "pi"`、`role: "implementer"`、`toolProfile: "write"` 的受限 writer,只把已经通过 Markdown gate 的最终用例转换为 pytest 资产。
6
6
 
7
- Do **not** create a new executor type. This is a standard `executor: pi` writer node.
7
+ ## 当前合同
8
8
 
9
- ## Recommended DAG Node Shape
10
-
11
- ```json
12
- {
13
- "id": "generate-backend-pytest-pi",
14
- "depends_on": ["backend-test-case-manifest-shell", "validate-backend-test-contracts-shell"],
15
- "complexity": "HIGH",
16
- "executor": "pi",
17
- "role": "implementer",
18
- "toolProfile": "write",
19
- "writePolicy": "exclusive",
20
- "writeSet": ["testcase/**/test_*.py", "testcase/**/helpers/**", "testcase/**/factories/**"],
21
- "allowedPaths": ["**"],
22
- "forbiddenPaths": [".harness/**", "artifacts/**"],
23
- "outputContract": "Pytest test files under testcase/ with 1:1 mapping to functional test case IDs; optional helpers/factories. Summary lists generated files, test function count, and any skipped cases with reasons.",
24
- "subtask_prompt_markdown": "./backend-test-dag.generate-pytest.prompt.md"
25
- }
26
- ```
27
-
28
- ## Prompt Body
29
-
30
- You are the Backend Test DAG **pytest code generator**.
31
-
32
- Your job is to convert reviewed test cases under `testcase/md/` into pytest automation code. Write test files under `testcase/` only. Stay within `writeSet`. Do not write root `artifacts/**`.
33
-
34
- ### Output Steps (do in order)
35
-
36
- 1. First, output a brief summary: how many files, how many test functions planned
37
- 2. Then write each test file under `testcase/`
38
-
39
- ### Inputs
40
-
41
- 1. **Validated test cases and manifest** — files under `testcase/md/` plus run-owned `contracts/backend-test-case-manifest.json`. The case review runs independently as advisory evidence.
42
- 2. **Validated Backend Test Analysis v2** — run-owned `contracts/backend-test-analysis.json`.
43
- 3. **Validated Backend Test Execution Contract v1** — run-owned `contracts/backend-test-execution.json` from `backend-test-execution-contract-shell` (fixtures, env *names*, `testRoot`, `targetMode`, authenticationMode).
44
- 4. **Target project conventions** — read `conftest.py`, `pytest.ini` / `pyproject.toml` to understand conventions, but do NOT modify them.
45
-
46
- Do NOT re-read source documents for free-form analysis. Use only validated cases, manifest, and contracts. Use only fixture/env/testRoot facts already present in the execution contract; never invent production credentials or secret values.
47
-
48
- When `targetMode` is `in-process` (including demoted local npm/node managed servers): bootstrap the service inside function-scoped pytest fixtures under `testcase/**` (for example subprocess `node server.js` / `startWelcomeServer` with `PORT=0`). Never require host-injected base URL env vars such as `WELCOME_BASE_URL` / `API_BASE_URL` — the clean-env pytest shell will not provide them.
49
-
50
- ### Conversion Rules
51
-
52
- #### File Naming
53
-
54
- - Every test file must start with `test_` prefix (e.g. `test_order.py`, `test_user_api.py`)
55
- - pytest collects tests from files matching `test_*.py` or `*_test.py` — use `test_` prefix exclusively
56
- - Never create test files without the `test_` prefix
57
-
58
- #### Write Boundary
59
-
60
- - Only **create new** files under writeSet:
61
- - `testcase/**/test_*.py`
62
- - `testcase/**/helpers/**` (optional pure helpers)
63
- - `testcase/**/factories/**` (optional test data factories)
64
- - Do NOT modify existing files: `conftest.py`, `pytest.ini`, `pyproject.toml`, `setup.cfg`, `__init__.py`, or any other framework/config file
65
- - Reuse existing fixtures; if required helpers are missing, create NEW helper/factory modules under the writeSet paths above — never edit root conftest
66
- - Read existing framework files to understand conventions, but treat them as immutable
67
- - Do NOT write production code, `.env`, secrets, or credential files
68
-
69
- #### Naming Conflict Resolution
70
-
71
- - If a file with the target name already exists under `testcase/`, add a numeric suffix: `test_order.py` → `test_order_01.py` → `test_order_02.py`
72
- - Never overwrite or append to existing files — each test script must be a standalone file
73
- - Check for existing files before writing; if `test_<module>.py` exists, use `test_<module>_01.py`
74
-
75
- #### 1:1 Traceability
76
-
77
- Every functional test case ID (`BE-<MODULE>-<NNN>`) must map to exactly one pytest function:
9
+ - 输入:最终 `testcase/md/**`、run-owned 环境报告与 Markdown 校验报告,以及有界的 pytest config / `conftest.py`。
10
+ - 禁止重新读取 `source/**`、新增测试场景、重新分配 AC、执行 pytest、修改生产代码/配置或输出业务 JSON。
11
+ - 写入范围:`testcase/**/test_*.py`、`testcase/**/helpers/**`、`testcase/**/factories/**`。
12
+ - pytest 可以使用模块级 `test_*` 函数,也可以使用 pytest 测试类中的 `test_*` 方法;不得为了追溯强迫目标项目放弃现有 class-based 风格。
13
+ - 每个最终 Markdown Case ID 必须出现在至少一个真实测试函数/方法区域中,优先同时出现在函数/方法名和 docstring:
78
14
 
79
15
  ```python
80
- # testcase/md/BE-ORDER-001 → testcase/test_order.py
81
- def test_BE_ORDER_001_create_order_with_valid_data():
82
- """BE-ORDER-001: Create order with valid request body."""
83
- ...
16
+ class TestOrderApi:
17
+ def test_BE_ORDER_001_create_order(self) -> None:
18
+ """BE-ORDER-001 创建合法订单。"""
19
+ ...
84
20
  ```
85
21
 
86
- - Function name: `test_<CASE_ID_with_underscores>` (e.g. `test_BE_ORDER_001_...`)
87
- - Docstring first line: `<CASE_ID>: <Case Title>`
88
-
89
- #### File Organization
90
-
91
- - All test files go under `testcase/` directory in the host project root
92
- - Group test files by MODULE segment: `BE-ORDER-*` → `testcase/test_order.py`, `BE-USER-*` → `testcase/test_user.py`
93
- - Follow existing project conventions for import style, fixture scope
94
-
95
- #### Fixture Strategy
96
-
97
- - Reuse existing project fixtures from `conftest.py` when available (read-only)
98
- - Do not create or modify root fixture/configuration files (`conftest.py`, pytest.ini, …)
99
- - Optional NEW helpers/factories may live under `testcase/**/helpers/**` or `testcase/**/factories/**` only
100
- - Prefer `@pytest.fixture(scope="function")` for test isolation
101
- - Use `@pytest.mark.parametrize` for boundary condition cases with multiple inputs
102
-
103
- #### Test Integrity
104
-
105
- - Tests verify implementation correctness — if a test fails, the implementation likely has a bug, not the test
106
- - Do NOT weaken assertions, remove test cases, or modify test logic to make tests pass
107
- - Do NOT add workarounds, skips, or try/except blocks to hide failures without explicit justification
108
- - Report all failures honestly in the output; the downstream `execute-backend-pytest-shell` node captures exit codes and stdout/stderr as-is
109
-
110
- #### Test Data Preparation Rules (MUST follow)
111
-
112
- **When Setup is Needed**
113
-
114
- Setup phase is REQUIRED only when test cases need pre-existing data:
115
- - Query/Read APIs: need data to exist before querying
116
- - Update/Delete APIs: need data to exist before modifying
117
- - State transition tests: need data in specific state
118
-
119
- Setup phase is NOT needed for:
120
- - Create APIs: testing the creation itself
121
- - Validation tests: testing input validation with invalid data
122
-
123
- **Data Setup Strategy**
124
-
125
- When setup is needed:
126
- 1. Use `@pytest.fixture(scope='module')` or `@pytest.fixture(scope='session')` to prepare shared test data
127
- 2. All test cases in the file share the same pre-constructed data
128
-
129
- **Data Construction Priority**
130
-
131
- 1. **API-first**: Use documented APIs from `analyze-inputs-pi` / reviewed cases
132
- 2. **Reuse existing conftest fixtures** (read-only)
133
- 3. **Direct DB writes are last resort** and only via safe test-DB fixtures with rollback/isolation
134
- 4. If neither API nor safe DB fixture exists, **skip with an explicit gap note** — do not invent credentials or touch live data
135
-
136
- **API Data Construction**
137
-
138
- - Prefer the `analyze-inputs-pi` API Endpoints section and reviewed cases for method/path/fields
139
- - Chain API calls only when cases document multi-step preconditions
140
- - Store created resource IDs in fixtures for reuse
141
- - Do **not** broadly search host route/controller trees for secrets, `.env`, private keys, or production configs
142
- - Read host API definitions only when needed to resolve a field name already referenced by reviewed cases
143
-
144
- **Database Data Construction (restricted)**
145
-
146
- - Allowed only via existing `conftest.py` test-DB fixtures with transaction rollback or equivalent isolation
147
- - Never hardcode connection strings, passwords, tokens, or cloud credentials
148
- - Never target production/shared non-test databases
149
- - If isolation is unclear, report the gap instead of writing DB rows
150
-
151
- #### Assertion Rules (MUST follow)
152
-
153
- **Positive Path (成功场景)**
154
-
155
- MUST assert ALL of the following:
156
- 1. HTTP status code: as defined in API spec (e.g. 200, 201)
157
- 2. Response structure: key fields exist in response body
158
- 3. Specific values: each field equals expected value from test case
159
- 4. Data type: each field is correct type
160
-
161
- **Negative Path (异常场景)**
162
-
163
- MUST assert ALL of the following:
164
- 1. HTTP status code: as defined in API spec (e.g. 400, 404, 500)
165
- 2. Error code field: field name from API spec (e.g. code, error_code, errcode, ret)
166
- 3. Error message field: field name from API spec (e.g. message, msg, errmsg, error)
167
-
168
- **Field Name Resolution**
169
-
170
- Field names MUST come from the upstream `analyze-inputs-pi` output (API Endpoints section), NOT hardcoded. For example:
171
- - If API spec defines `{"ret": 0, "msg": "success"}`, assert `response.json()["ret"]` and `response.json()["msg"]`
172
- - If API spec defines `{"code": 4001, "message": "error"}`, assert `response.json()["code"]` and `response.json()["message"]`
173
-
174
-
175
- #### Conditional Test Implementation (include ONLY if test cases exist)
176
-
177
- - **Authentication tests**: implement ONLY if `testcase/md/` contains auth-related cases
178
- - Use `@pytest.mark.auth` marker
179
- - Test no token, expired token, invalid token, insufficient permissions, cross-user access
180
- - **Timeout tests**: implement ONLY if `testcase/md/` contains timeout-related cases
181
- - Use `@pytest.mark.timeout` marker
182
- - Use `unittest.mock.patch` or `pytest-mock` to simulate slow responses
183
- - If no such cases exist in the reviewed test cases, do NOT add these tests
184
-
185
- #### Markers
186
-
187
- - `@pytest.mark.positive` — happy path cases
188
- - `@pytest.mark.negative` — error/exception cases
189
- - `@pytest.mark.boundary` — edge cases
190
- - `@pytest.mark.<MODULE>` — module-specific marker (e.g. `@pytest.mark.order`)
191
-
192
- #### Skip Policy
193
-
194
- If a test case cannot be automated (requires external service not mockable, requires manual verification), add it with `@pytest.mark.skip(reason="...")` and document the reason. Do not omit the function — traceability requires it exists.
22
+ - 断言只来自 `### 预期结果` / `### Expected Results`;setup 只来自 `### 前置条件`、`### 测试数据`、`### 自动化映射` 或对应历史英文分节。
23
+ - 禁止 `skip` / `xfail`、吞断言、宽异常静默通过、mock 替代真实目标、删除用例或弱化断言。
24
+ - best-effort 清理只能捕获所选 HTTP client 实际抛出的窄 transport exception,例如 `requests.RequestException` 或 `urllib.error.URLError`;禁止 `except:`、`except Exception`、`except BaseException` 后 `pass`。
25
+ - 同一 Case ID 可以由多个 pytest 函数覆盖;额外映射会进入 traceability 报告,但不能伪造未在 Markdown 中定义的业务场景。
26
+ - 测试失败必须诚实保留,后续节点只执行一次 pytest,并从同一 JUnit 生成 HTML/facts。
195
27
 
196
- ### Output Shape (after summary line)
28
+ ## 推荐输出
197
29
 
198
- After the mandatory summary line, provide:
30
+ 写入文件后,用简短中文总结:
199
31
 
200
- 1. **Generated Files** — list of files written under `tests/backend/`.
201
- 2. **Function Mapping Table** — `| Test Case ID | Pytest Function | File | Marker |`.
202
- 3. **Skipped Cases** — if any, list with reason.
203
- 4. **Conventions Observed** — note project fixtures/config discovered and followed.
204
- 5. **Residual Risks** — cases that may need manual verification or environment setup.
32
+ 1. 生成或更新了哪些测试文件;
33
+ 2. Case ID 脚本 pytest 函数/方法映射;
34
+ 3. 复用的 fixture/config;
35
+ 4. 仍存在的环境或自动化缺口。
205
36
 
206
- Do not include chain-of-thought. Do not write root `artifacts/**`.
37
+ 不得输出 chain-of-thought,不得执行 pytest。
@@ -68,8 +68,8 @@
68
68
  "executorModels": {
69
69
  "pi": {
70
70
  "LOW": "gpt-5.3-codex-spark",
71
- "MED": "glm-5.2",
72
- "HIGH": "gpt-5.5"
71
+ "MED": "grok-4.5",
72
+ "HIGH": "gpt-5.6-sol"
73
73
  }
74
74
  },
75
75
  "tasks": [
@@ -124,8 +124,8 @@
124
124
  ".harness/dag-runs/**",
125
125
  "artifacts/**"
126
126
  ],
127
- "outputContract": "Write testcase/md/README.md plus module Markdown cases using BE-<MODULE>-<NNN>. Use Chinese for human-readable content while preserving required machine-readable identifiers and section headings; no JSON, pytest execution, production code or config writes.",
128
- "subtask_prompt": "Read the upstream environment report. Generate a Markdown-first backend test strategy and cases under testcase/md/**.\n\nWrite human-readable content in Simplified Chinese by default: document titles, case titles, strategy explanations, preconditions, test-data descriptions, step descriptions, expected-result descriptions, automation notes, table headers and evidence-gap explanations. Keep English only where it is part of a machine-readable contract or established technical literal, including Case IDs, AC/REQ/BR IDs, exact section headings, HTTP methods, paths, field names, enum values, commands, filenames, code symbols and source citations. Do not add an English translation when Chinese already conveys the meaning.\n\nEvery case heading is `## BE-<MODULE>-<NNN> <中文用例标题>` and contains these exact machine-readable headings: `### Acceptance Criteria`, `### Source References`, `### Preconditions`, `### Test Data`, `### Steps`, `### Expected Results`, and `### Automation Notes`. API cases also contain `### Endpoint` with Method and Path. Under those headings, write descriptions in Chinese while preserving exact IDs, values and protocol literals.\n\nCreate testcase/md/README.md in Chinese. It should concisely explain the test objective, environment/target, isolation and cleanup strategy, module index, traceability summary, assertion principles, evidence gaps and non-goals. Prefer readable Chinese tables and lists over repeated boilerplate.\n\nExpected Results must be concrete, independently assertable Chinese statements. Each result should name the observable HTTP status, response field/value, state transition or membership condition instead of vague phrases such as ‘works correctly’ or ‘符合预期’. Steps must be executable and ordered. Use only environment-supported fixtures/targets/isolation. Record evidence gaps in Chinese instead of inventing behavior or credentials. Do not emit JSON, pytest, or execute commands.\n\n## Derived task contract: 需求.md\n\n# Backend test\n- AC-001 proof\n\n## Authoritative reference index\n\n[]\n\nFor each index entry, use `readPath` for Pi read-tool calls and copy `path` exactly into Markdown Source References. Bound files under .harness/tasks/<taskId>/source/** are read-only inputs: reading them is allowed even though writing .harness/** is forbidden. Never resolve `path` relative to the repository root, search for substitutes, or fall back to docs/** when a bound read fails.\n\nRead only precise indexed references needed for AC/API/field/rule evidence; references remain authoritative over derived text."
127
+ "outputContract": "Write a Chinese, human-readable testcase/md/README.md plus module Markdown case cards using BE-<MODULE>-<NNN>; keep machine IDs/literals exact and do not execute pytest or modify production code/config.",
128
+ "subtask_prompt": "Read the upstream environment report. Generate a Markdown-first backend test strategy and cases under testcase/md/**.\n\nWrite human-readable content in Simplified Chinese by default. Keep English only for machine-readable IDs and technical literals such as Case/AC/REQ/BR IDs, HTTP methods, paths, field names, enum values, commands, filenames, code symbols and exact source citations.\n\nCreate testcase/md/README.md as the concise entry page: test objective, target/environment, isolation/cleanup, module summary and a linked case index table with Case ID, Chinese case name, scenario type, endpoint and expected status/result. Avoid repeating every case body in README.\n\nWrite each module as readable case cards. Every case starts with `## BE-<MODULE>-<NNN>|<中文用例名称>` and uses these Chinese headings: `### 测试目的`, `### 验收标准`, `### 需求依据`, `### 前置条件`, optional `### 测试数据`, `### 操作步骤`, `### 预期结果`, and `### 自动化映射`. API metadata may use a compact table under the case heading. The deterministic validator also accepts legacy English headings, but new output should use this Chinese presentation.\n\nPlace steps and their expected results in a compact readable table when that improves clarity; otherwise keep numbered executable steps and numbered/bulleted independently assertable results. Every result must name the observable HTTP status, response field/value, state transition or membership condition, never vague wording such as ‘符合预期’.\n\nIn `自动化映射`, record the planned script path and pytest function name when known. Put implementation-only restrictions in a concise `<details>` block rather than dominating the main case flow. Use only environment-supported fixtures/targets/isolation, record evidence gaps in Chinese, and do not emit JSON, pytest, or execute commands.\n\n## Derived task contract: 需求.md\n\n# Backend test\n- AC-001 proof\n\n## Authoritative reference index\n\n[]\n\nFor each index entry, use `readPath` for Pi read-tool calls and copy `path` exactly into Markdown Source References. Bound files under .harness/tasks/<taskId>/source/** are read-only inputs: reading them is allowed even though writing .harness/** is forbidden. Never resolve `path` relative to the repository root, search for substitutes, or fall back to docs/** when a bound read fails.\n\nRead only precise indexed references needed for AC/API/field/rule evidence; references remain authoritative over derived text."
129
129
  },
130
130
  {
131
131
  "id": "review-and-revise-backend-md-cases-pi",
@@ -149,7 +149,7 @@
149
149
  "artifacts/**"
150
150
  ],
151
151
  "outputContract": "Review source fidelity and directly revise only testcase/md/**; return concise Markdown, never JSON.",
152
- "subtask_prompt": "Independently review generated Markdown cases against each case Source References and environment evidence. Preserve and improve the Simplified Chinese presentation: human-readable titles, prose, table headers, steps, expected results and notes should be Chinese unless the token is a machine-readable ID, exact required heading, HTTP/API literal, field/enum value, path, filename, command or code symbol.\n\nCheck AC completeness/meaning, endpoint, fields/shape, status/error codes, rules, states, documented boundaries/auth, positive/negative coverage, executable steps and assertable results. Also reject avoidable English prose, duplicated bilingual wording, vague Chinese results such as ‘符合预期’, and literal translations that obscure the observable assertion.\n\nCorrect testcase/md/** directly: add documented omissions, remove unsupported cases, fix mappings/expectations, merge duplicates, improve unclear Chinese wording, or record gaps in Chinese. Do not translate or alter Case IDs, AC/REQ/BR IDs, exact required section headings, HTTP methods, paths, field names, enum values, filenames, code symbols or Source References. Avoid cosmetic rewrites that do not improve correctness or readability.\n\nRead only precise referenced source paths plus requirement sections needed for uncovered ACs. Do not scan the repository, modify source/**, generate pytest, execute tests, or emit JSON.\n\n## Derived task contract: 需求.md\n\n# Backend test\n- AC-001 proof\n\n## Authoritative reference index\n\n[]\n\nFor each index entry, use `readPath` for Pi read-tool calls and keep `path` as the exact Markdown Source References citation. Bound files under .harness/tasks/<taskId>/source/** are read-only inputs: reading them is allowed even though writing .harness/** is forbidden. Never resolve `path` relative to the repository root, search for substitutes, or fall back to docs/** when a bound read fails."
152
+ "subtask_prompt": "Independently review generated Markdown cases against each case 需求依据 and environment evidence. Treat the files as human-facing test documentation: require a clear Chinese name and scenario/purpose, compact metadata, readable steps/results, and a concise automation mapping while preserving exact machine IDs and technical literals.\n\nCheck AC completeness/meaning, endpoint, fields/shape, status/error codes, rules, states, documented boundaries/auth, positive/negative coverage, executable steps and assertable results. Reject avoidable English prose, duplicated bilingual wording, repeated boilerplate, oversized unstructured sections, vague results such as ‘符合预期’, and missing script/function mapping where it can be derived.\n\nCorrect testcase/md/** directly: add documented omissions, remove unsupported cases, fix mappings/expectations, merge duplicates, improve navigation/tables/Chinese wording, or record gaps in Chinese. Keep Case IDs, AC/REQ/BR IDs, HTTP methods, paths, fields, enum values, filenames, code symbols and source citations exact. The validator accepts Chinese and legacy English section aliases; retain or converge to the Chinese human-readable headings without losing structure.\n\nRead only precise referenced source paths plus requirement sections needed for uncovered ACs. Do not scan the repository, modify source/**, generate pytest, execute tests, or emit JSON.\n\n## Derived task contract: 需求.md\n\n# Backend test\n- AC-001 proof\n\n## Authoritative reference index\n\n[]\n\nFor each index entry, use `readPath` for Pi read-tool calls and keep `path` as the exact Markdown Source References citation. Bound files under .harness/tasks/<taskId>/source/** are read-only inputs: reading them is allowed even though writing .harness/** is forbidden. Never resolve `path` relative to the repository root, search for substitutes, or fall back to docs/** when a bound read fails."
153
153
  },
154
154
  {
155
155
  "id": "validate-backend-md-cases-shell",
@@ -203,7 +203,7 @@
203
203
  "artifacts/**"
204
204
  ],
205
205
  "outputContract": "Convert every final automatable Markdown case into pytest assets whose actual test function region contains the exact Case ID, preferably in the function name or docstring; no JSON and no pytest execution.",
206
- "subtask_prompt": "Convert validated testcase/md/** to pytest using upstream environment and validation evidence plus only bounded pytest config/conftest.\n\nEnsure every final Markdown Case ID appears in at least one real top-level test_* function region, preferably as `test_BE_<MODULE>_<NNN>_<description>` or in that function's docstring. Multiple test functions may cover one Case ID; assertions come only from Expected Results and setup comes only from Preconditions/Test Data/Automation Notes.\n\nDo not read source/**, add cases, reassign ACs, modify conftest/config/production code, use skip/xfail, swallow assertions, execute pytest, or emit JSON."
206
+ "subtask_prompt": "Convert validated testcase/md/** to pytest using upstream environment and validation evidence plus only bounded pytest config/conftest.\n\nEnsure every final Markdown Case ID appears in at least one real pytest test function or pytest test class method region, preferably as `test_BE_<MODULE>_<NNN>_<description>` and in that function/method docstring. Module-level functions and class-based pytest methods are both supported. Multiple test functions may cover one Case ID; assertions come only from 预期结果/Expected Results and setup comes only from 前置条件/测试数据/自动化映射 or their legacy English aliases.\n\nDo not read source/**, add cases, reassign ACs, modify conftest/config/production code, use skip/xfail, swallow assertions, execute pytest, or emit JSON. For best-effort cleanup, catch only the narrow transport exception actually raised by the selected HTTP client (for example `requests.RequestException` or `urllib.error.URLError`); never use bare `except`, `Exception`, or `BaseException` with `pass`."
207
207
  },
208
208
  {
209
209
  "id": "backend-test-traceability-gate-shell",
@@ -224,7 +224,7 @@
224
224
  "artifacts/**"
225
225
  ],
226
226
  "outputContract": "Run-owned reports/backend-test-traceability.md proving every real Markdown Case ID is covered by at least one pytest test function.",
227
- "subtask_prompt": "Fail closed only when a real Markdown case heading has no associated top-level pytest test function. Accept exact Case IDs in the function name or its decorator/body/docstring region; report multiple mappings and extra automation Case IDs without blocking. Continue to reject skip/xfail or swallowed exceptions.",
227
+ "subtask_prompt": "Fail closed only when a real Markdown case heading has no associated pytest test function or class method. Accept exact Case IDs in the function/method name or its decorator/body/docstring region; report multiple mappings and extra automation Case IDs without blocking. Continue to reject skip/xfail or swallowed exceptions.",
228
228
  "shell": {
229
229
  "commands": [],
230
230
  "backendTestPipeline": "markdown-traceability",
@@ -251,7 +251,7 @@
251
251
  "artifacts/**"
252
252
  ],
253
253
  "outputContract": "One pytest execution producing valid JUnit, self-contained HTML and reports/backend-test-facts.md; exit 0/1 with valid evidence continues.",
254
- "subtask_prompt": "Execute pytest exactly once. Validate JUnit, render self-contained HTML from that JUnit without rerun, and preserve failures as facts.",
254
+ "subtask_prompt": "Execute pytest exactly once. Validate JUnit, render the primary self-contained Chinese HTML report from the same JUnit plus final Markdown case metadata without rerun, list every case with name/scenario/script/function/result/duration, and preserve failure summaries plus expandable technical details as facts.",
255
255
  "shell": {
256
256
  "commands": [
257
257
  "mkdir -p \"${HARNESS_DAG_RUN_DIR}/reports\"; PYTHONUTF8=1 PYTHONIOENCODING=utf-8 PYTHONDONTWRITEBYTECODE=1 python -m pytest testcase/ -v -p no:cacheprovider --junitxml=\"${HARNESS_DAG_RUN_DIR}/reports/backend-test.junit.xml\"; STATUS=$?; printf \"%s\" \"${STATUS}\" > \"${HARNESS_DAG_RUN_DIR}/reports/backend-test-pytest-exit.txt\"; if { [ \"${STATUS}\" -eq 0 ] || [ \"${STATUS}\" -eq 1 ]; } && [ -s \"${HARNESS_DAG_RUN_DIR}/reports/backend-test.junit.xml\" ]; then exit 0; fi; exit \"${STATUS}\""
@@ -2,88 +2,35 @@
2
2
 
3
3
  ## Purpose
4
4
 
5
- Use this prompt for the single read-only **backend test case review** node: `executor: "pi"`, `role: "reviewer"`, `writePolicy: "read-only"`. The reviewer audits generated backend functional test cases for completeness, format compliance, and traceability to source requirements. The verdict is advisory evidence consumed by canonical context, retrospective, and L-5; it neither authorizes nor blocks the pytest writer.
5
+ `review-and-revise-backend-md-cases-pi` 使用。该节点是 `executor: "pi"`、`role: "reviewer"`、`toolProfile: "write"` 的受限 reviewer,只能直接修订 `testcase/md/**`,不得生成 pytest 或修改任务源、生产代码和配置。
6
6
 
7
- Do **not** create `executor: reviewer`. Reviewer is a **role** on `executor: pi`.
7
+ ## 当前合同
8
8
 
9
- ## Recommended DAG Node Shape
9
+ Markdown 用例视为面向测试、研发、产品与评审人员的正式文档,而不是模型中间产物。
10
10
 
11
- ```json
12
- {
13
- "id": "review-backend-cases-pi",
14
- "depends_on": ["backend-test-case-manifest-shell", "backend-test-analysis-contract-shell"],
15
- "complexity": "HIGH",
16
- "executor": "pi",
17
- "role": "reviewer",
18
- "writePolicy": "read-only",
19
- "allowedPaths": ["**"],
20
- "forbiddenPaths": [".harness/**", "artifacts/**"],
21
- "outputContract": "Plain Markdown whose first non-empty line is VERDICT: pass or VERDICT: request-revision; followed by Findings and Coverage Assessment. No file writes.",
22
- "subtask_prompt_markdown": "./backend-test-dag.review-cases.prompt.md"
23
- }
24
- ```
11
+ ### 阅读体验
25
12
 
26
- ## Prompt Body
13
+ - `testcase/md/README.md` 是简洁入口,包含测试目标、环境、隔离/清理策略、模块汇总和可跳转的用例索引。
14
+ - 模块文件采用中文用例卡片;每条以 `## BE-<MODULE>-<NNN>|<中文用例名称>` 开始。
15
+ - 新文档优先使用:`测试目的`、`验收标准`、`需求依据`、`前置条件`、`测试数据`、`操作步骤`、`预期结果`、`自动化映射`。
16
+ - validator 同时接受上述中文分节和历史英文分节;机器 ID、HTTP 方法、路径、字段、枚举、文件名、函数名与 source citation 必须保持精确。
17
+ - 步骤和预期可以用紧凑表格,也可以分别使用编号/项目列表;必须可执行、可独立断言。
18
+ - 自动化内部限制应简短或放进 `<details>`,不能淹没人类主要阅读路径。
27
19
 
28
- You are the Backend Test DAG **test case reviewer** (read-only).
20
+ ### 正确性
29
21
 
30
- Your job is to audit the generated backend functional test cases for completeness, format compliance, requirement coverage, and traceability. You are **not** an implementer or test generator. Do not edit repository files, including root `artifacts/**`.
22
+ - 对照每条 `需求依据` 和环境报告检查 AC、接口、字段/响应形状、状态码、错误语义、状态转换、正向/异常/边界场景。
23
+ - 删除无依据场景、合并重复用例、补齐有依据的遗漏;无法确认的内容写入中文证据缺口,不猜测行为或凭据。
24
+ - 拒绝“符合预期”“正常工作”等模糊结果,以及无意义的中英双写和大段重复 boilerplate。
25
+ - 若能确定脚本与函数命名,在 `自动化映射` 中写明计划脚本路径与 pytest 函数/方法名。
31
26
 
32
- ### Mandatory First Line
27
+ ## 推荐输出
33
28
 
34
- The **first non-empty line** of your response must be exactly one of:
29
+ 完成文件修订后,仅用简短中文说明:
35
30
 
36
- - `VERDICT: pass`
37
- - `VERDICT: request-revision`
31
+ - 修订了哪些文档;
32
+ - 用例数与主要模块;
33
+ - 修复了哪些需求一致性或阅读问题;
34
+ - 仍有哪些证据缺口。
38
35
 
39
- No preamble, heading, or blank lines before the verdict line.
40
-
41
- ### Inputs to Review
42
-
43
- 1. **Acceptance criteria / analysis** — from the validated Backend Test Analysis v1 artifact materialized by `backend-test-analysis-contract-shell` (`contracts/backend-test-analysis.json` under the current DAG run). Do not treat free-form Markdown from `analyze-inputs-pi` as the contract.
44
- 2. **Case Manifest v1** — `contracts/backend-test-case-manifest.json` (schemaId `backend-test-case-manifest-v1`). Prefer `coverageSummary` and caseId↔acIds from this artifact; do not invent coverage percentages.
45
- 3. **Generated test cases** — files under `testcase/md/`.
46
-
47
- Do NOT re-read source documents. Use the validated analysis artifact, case manifest, and generated cases only.
48
-
49
- ### Review Checklist
50
-
51
- | Area | Check | Severity if Missing |
52
- |------|-------|---------------------|
53
- | **ID format** | Every test case ID matches `BE-<MODULE>-<NNN>` (e.g. `BE-ORDER-001`) | Critical |
54
- | **Positive path coverage** | Happy-path scenarios for each acceptance criterion | Critical |
55
- | **Negative path coverage** | Error/exception scenarios (invalid input, not found, state violations) | Important |
56
- | **Boundary conditions** | Edge cases (empty input, max length, edge values) | Important |
57
- | **State transitions** | Illegal state changes covered | Important |
58
- | **Requirement traceability** | Each acceptance criterion (AC-xxx) maps to at least one test case ID (manifest coverageSummary or evidenceGaps) | Critical |
59
- | **Manifest consistency** | Markdown case bodies **and** any AC matrix list the **same full** `BE-*` ids as Case Manifest v1 `caseId`→`acIds`. Never claim "all cases" / "全部用例" cover an AC unless every case maps that AC. | Critical |
60
- | **Planned automation** | Missing `test_*.py` before generate-pytest is **Informational only**, not Critical | Informational |
61
- | **Out-of-scope ACs** | Flyway / frontend e2e / `mvn test` etc. already in manifest `evidenceGaps` must not be treated as uncovered Critical | Informational |
62
- | **Case structure** | Each case has: ID, Title, Precondition, Steps, Expected Result | Important |
63
- | **No duplicate IDs** | All test case IDs are unique across files | Critical |
64
-
65
- ### Conditional Coverage (check ONLY if mentioned in upstream analysis)
66
-
67
- - **Authentication coverage**: check ONLY if the validated analysis artifact mentions auth mechanism (JWT, OAuth2, API Key, etc.)
68
- - **Timeout coverage**: check ONLY if the validated analysis artifact mentions timeout handling or degradation strategy
69
- - If not mentioned in the validated analysis artifact, do NOT flag as missing
70
-
71
- ### Verdict Rules
72
-
73
- | Condition | Verdict |
74
- |-----------|---------|
75
- | All Critical checks pass, Important checks have no more than 2 findings | `VERDICT: pass` |
76
- | Any Critical check fails | `VERDICT: request-revision` |
77
- | More than 2 Important findings | `VERDICT: request-revision` |
78
- | Only Informational findings | `VERDICT: pass` (with findings listed) |
79
-
80
- ### Output Shape (after verdict line)
81
-
82
- 1. **Coverage Assessment** — table mapping each AC to covering **full** test case IDs (or "uncovered" / gap).
83
- 2. **Findings** — bullet list tagged `Critical`, `Important`, or `Informational`.
84
- 3. **Statistics** — total case count, positive/negative/boundary breakdown, module distribution.
85
- 4. **Required follow-up** (only when `request-revision`) — numbered, concrete MD corrections for a separate follow-up task. These findings do not authorize edits in the current run.
86
-
87
- ### Fail-fast note
88
-
89
- There is no final review or in-run revision writer. Any `request-revision` verdict remains auditable advisory evidence and must be reported downstream; it does not stop pytest generation.
36
+ 不得输出 JSON,不得执行测试。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tea-agent/loop-agent",
3
- "version": "0.19.0",
3
+ "version": "0.20.1-beta.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "loop-agent": "bin/loop-agent.js",
@@ -10,9 +10,11 @@ references:
10
10
  # Frontend Design Review
11
11
 
12
12
  For frontend design review nodes. Read the checklist; audit contract, scout, Mock
13
- strategy, effective plan, task bounds, and traceable design evidence. The knowledge-
14
- base connector is TODO: never invent results. If unavailable or unmatched, require
15
- `<repoRoot>/openspec/**` search/read evidence before repository conventions.
13
+ strategy, effective plan, task bounds, and traceable design evidence.
14
+ Knowledge base and `openspec/` are parallel specification sources. Query the
15
+ knowledge-base connector when available; regardless of result, also search and
16
+ read `<repoRoot>/openspec/**` before accepting repository conventions. The
17
+ connector format is TODO: never invent results.
16
18
 
17
19
  ## Verdict Contract
18
20
 
@@ -9,8 +9,9 @@
9
9
  ## Project Fit
10
10
 
11
11
  - Reuse components, hooks, API helpers, mocks, schemas, router patterns, tokens, and theme rules.
12
- - Cite knowledge-base or `openspec/`; failed/empty knowledge queries must search `<repoRoot>/openspec/**`.
13
- - Record source status, query terms, paths/headings, conflicts, authorized deps, and allowed paths.
12
+ - Cite knowledge base and `openspec/` as parallel sources; failed or empty
13
+ knowledge queries must still search `<repoRoot>/openspec/**`.
14
+ - Record source status, query terms, paths/headings, conflicts, authorized deps, and allowed paths for both.
14
15
 
15
16
  ## Interaction / Quality
16
17