@tea-agent/loop-agent 0.18.1 → 0.20.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.
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +33 -0
- package/README.md +4 -6
- package/dist/application/dag/generate-task-dag.js +12 -1
- package/dist/commands/init.js +3 -3
- package/dist/executors/shell-executor.js +188 -2
- package/dist/governance/exec-plans.js +4 -0
- package/dist/worker/cli.js +13 -12
- package/dist/worker/console/doctor.js +55 -2
- package/dist/worker/console/index.js +1 -0
- package/dist/worker/console/loopback.js +2 -2
- package/dist/worker/console/observe-link.js +7 -2
- package/dist/worker/console/operator-actions.js +30 -2
- package/dist/worker/console/operator-selection.js +92 -0
- package/dist/worker/console/operator-surface-health.js +23 -0
- package/dist/worker/console/recovery-cta.js +2 -2
- package/dist/worker/console/routes.js +45 -19
- package/dist/worker/console/security.js +29 -4
- package/dist/worker/console/server.js +106 -8
- package/dist/worker/console/static/assets/index-3vsjZJHq.js +16 -0
- package/dist/worker/console/static/assets/index-i1wV4LrY.css +1 -0
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/observe/routes.js +63 -21
- package/dist/worker/observe/server.js +3 -10
- package/dist/worker/observe/static/index.html +6 -3
- package/dist/worker/observe/static/styles.css +53 -0
- package/dist/workflows/dag/backend-test-markdown-workflow.js +163 -41
- package/dist/workflows/dag/backend-test-result-contract.js +30 -7
- package/dist/workflows/dag/frontend-prewrite-gate.js +77 -0
- package/dist/workflows/dag/frontend-repair.js +7 -1
- package/dist/workflows/dag/frontend-review-context.js +43 -0
- package/dist/workflows/dag/frontend-verification-trace.js +34 -15
- package/dist/workflows/dag/governance-profile.js +14 -6
- package/dist/workflows/dag/init-hybrid.js +143 -399
- package/dist/workflows/dag/types.js +30 -0
- package/dist/workflows/dag/validate.js +22 -1
- package/docs/README.md +4 -2
- package/docs/architecture/evolution.md +6 -6
- package/docs/architecture/worker-and-feature.md +9 -9
- package/docs/templates/agent-dag.schema.json +40 -0
- package/docs/templates/backend-test-dag.generate-pytest.prompt.md +23 -192
- package/docs/templates/backend-test-dag.json +8 -8
- package/docs/templates/backend-test-dag.review-cases.prompt.md +22 -75
- package/package.json +1 -1
- package/skills/agent-worker/references/agent-worker-operator.md +2 -2
- package/skills/frontend-implementation/references/node-contracts.md +6 -8
- package/skills/frontend-review/SKILL.md +5 -8
- package/skills/loop-agent/references/command-reference.md +4 -2
- package/skills/loop-agent/references/harness-policy.md +1 -1
- package/skills/loop-agent/references/hybrid-dag.md +2 -2
- package/dist/worker/console/static/assets/index-KUSib7aM.js +0 -16
- package/dist/worker/console/static/assets/index-ucIzpaGJ.css +0 -1
|
@@ -113,6 +113,33 @@ 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
|
+
});
|
|
130
|
+
export const dagFrontendVerificationBundleSchema = z.object({
|
|
131
|
+
schemaVersion: z.literal(1),
|
|
132
|
+
mockCommands: z.array(z.string()).default([]),
|
|
133
|
+
staticCommands: z.array(z.string()).min(1),
|
|
134
|
+
behaviorCommands: z.array(z.string()).min(1),
|
|
135
|
+
mockEvidence: dagShellVerifyEvidenceSchema.optional(),
|
|
136
|
+
staticEvidence: dagShellVerifyEvidenceSchema,
|
|
137
|
+
behaviorEvidence: dagShellVerifyEvidenceSchema,
|
|
138
|
+
mode: z.enum(["initial", "repair"]),
|
|
139
|
+
});
|
|
140
|
+
export const dagFrontendReviewContextSchema = z.object({
|
|
141
|
+
schemaVersion: z.literal(1),
|
|
142
|
+
});
|
|
116
143
|
export const ENV_VAR_NAME_PATTERN = /^[A-Z_][A-Z0-9_]*$/;
|
|
117
144
|
export const dagVersionSchema = z
|
|
118
145
|
.union([z.literal(1), z.literal(2), z.literal(3), z.literal(4)])
|
|
@@ -191,6 +218,9 @@ export const dagShellConfigSchema = z.object({
|
|
|
191
218
|
}).strict().optional(),
|
|
192
219
|
requirementCoverageGate: dagRequirementCoverageGateSchema.optional(),
|
|
193
220
|
jsonArtifactGate: dagJsonArtifactGateSchema.optional(),
|
|
221
|
+
frontendPrewriteGate: dagFrontendPrewriteGateSchema.optional(),
|
|
222
|
+
frontendVerificationBundle: dagFrontendVerificationBundleSchema.optional(),
|
|
223
|
+
frontendReviewContext: dagFrontendReviewContextSchema.optional(),
|
|
194
224
|
backendTestPipeline: dagBackendTestPipelineSchema.optional(),
|
|
195
225
|
verifyEvidence: dagShellVerifyEvidenceSchema.optional(),
|
|
196
226
|
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 &&
|
|
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
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
**索引职责**:本文件只索引**核心契约、方法论、产物目录入口与模板**。单篇 progress / report / completed plan 的全量列表分别由对应子目录 `README.md` 维护,避免三处精选榜漂移。
|
|
8
8
|
|
|
9
|
-
**维护日:2026-07-22** — 索引对齐仓库头 `@tea-agent/loop-agent@0.
|
|
9
|
+
**维护日:2026-07-22** — 索引对齐仓库头 `@tea-agent/loop-agent@0.18.0`、reports 按类型分子目录,以及 progress / completed 导读制;版本与能力细节以 `CHANGELOG.md`、`reports/current-capability-summary.md` 与 active plans 为准。
|
|
10
10
|
|
|
11
11
|
站上用法文档在 `../website/docs/`;双树收敛见 `../skills/loop-agent/references/docs-converge.md`。
|
|
12
12
|
|
|
@@ -57,7 +57,8 @@
|
|
|
57
57
|
- `design/dag-source-binding-and-recovery.md` — 新生成 DAG 的任务源绑定与中断恢复
|
|
58
58
|
- `design/agent-worker-fullstack-workflow-integration.md` — workflow routing、Task Outcome、artifact-aware Ready、`fullstack-v1` 与 Verification Bundle
|
|
59
59
|
- `design/fullstack-end-to-end-delivery-optimization-roadmap.md` — 全栈端到端优化收敛路线图(release train / Delivery / Final Verification)
|
|
60
|
-
- `design/
|
|
60
|
+
- `design/2026-07-22-console-observe-unified-operator-surface.md` — Observe 深度融合进 Console(Wave 1–3 已实现,目标 0.18.0)
|
|
61
|
+
- `design/local-operator-console-from-pi-web.md` — Operator Console 设计输入;MVP 已随 `0.17.0`–`0.17.2` 发布;统一 surface 见上条
|
|
61
62
|
- `design/taskspec-to-loop-agent-mapping.md` — TaskSpec → loop-agent task 兼容契约(文档镜像;runtime 真源在代码)
|
|
62
63
|
|
|
63
64
|
已实现且仅作历史说明的设计见 `design/archive/`(例如 `design/archive/2026-07-14-loop-agent-self-update-notifier.md`)。
|
|
@@ -74,6 +75,7 @@
|
|
|
74
75
|
|
|
75
76
|
完整 completed 列表与主题速览见 `exec-plans/completed/README.md`。近期高频归档:
|
|
76
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
|
|
77
79
|
- `exec-plans/completed/2026-07-22-backend-markdown-gate-fix.md` — backend-test Markdown gate、traceability、中文生成与真实 Campaign 收口
|
|
78
80
|
- `exec-plans/completed/2026-07-22-backend-test-markdown-first-8-node.md` — backend-test Markdown-first 8 节点
|
|
79
81
|
- `exec-plans/completed/2026-07-22-backend-test-report-first-flow.md` — backend-test 报告优先 12 节点
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
本页区分 loop-agent **当前已实现**的架构能力与**未来规划**。当前事实以代码、发布 CLI、已完成计划为准;未来能力一律标「规划 / 未实现 / 前瞻」。权威源:`CHANGELOG.md`、`docs/reports/current-capability-summary.md`、ADR 0001–0005、`docs/exec-plans/completed/` 与 `docs/exec-plans/active/`。
|
|
4
4
|
|
|
5
|
-
**对照版本:`@tea-agent/loop-agent@0.
|
|
5
|
+
**对照版本:`@tea-agent/loop-agent@0.18.0`(2026-07-22)**。细节版本条目见根 `CHANGELOG.md`;本表只保留架构层可读摘要。
|
|
6
6
|
|
|
7
|
-
## 当前已实现(累计至 0.
|
|
7
|
+
## 当前已实现(累计至 0.18.0)
|
|
8
8
|
|
|
9
9
|
| 域 | 现状 | 权威入口 |
|
|
10
10
|
| --- | --- | --- |
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
| Backend-test | **Markdown-first 8 节点**(env → MD cases/review → 单次 pytest+HTML → report+L-5);历史 JSON 读兼容 | completed `2026-07-22-backend-test-markdown-first-8-node.md` |
|
|
21
21
|
| Frontend-test | 默认 short-chain RAG;结果链 / Outcome 投影;formal smoke 仍 active | `CHANGELOG.md [0.16.24]`;active success-rate plan |
|
|
22
22
|
| Frontend-implementation | Contract / trace / repair / Mock assess;条件 design/repair 分支 | `CHANGELOG.md [0.13.0]` / `[0.17.x]` |
|
|
23
|
-
| Observe |
|
|
24
|
-
| Local Operator Console | `agent-worker console serve\|doctor`(loopback);Happy Path / Interview /
|
|
23
|
+
| Inspect(原 Observe) | 统一 Console 的 `/inspect/` 只读运营面与富时间线;兼容期仍保留独立 `observe serve` | `website/docs/guides/observe-ui.md`、`CHANGELOG.md [Unreleased]` |
|
|
24
|
+
| Local Operator Console | `agent-worker console serve\|doctor`(loopback);Operate + Inspect、Happy Path / Interview / split view / recovery CTA;**非**远端多用户 Console | unify design;ADR 0005 |
|
|
25
25
|
| Task Contract / operator surface | journaled `task contract *`;machine envelope;**DagSpec v4 `taskContractBinding`**(exclusive writer 强制) | `CHANGELOG.md [0.17.0]`–`[0.17.2]`;ADR 0005 |
|
|
26
26
|
| DagSpec / repair | v3 `runtimeContract` + 显式 `repairNodeId`;新 writer 生成默认 v4 binding | `dag-execution.md`、`CHANGELOG.md [0.11.0]` / `[0.17.0]` |
|
|
27
27
|
| Eval Lab | corpus / campaign / promote(人工门禁);`autoPromote=false`;**非** RSI Level 1 | `CHANGELOG.md [0.15.0]`;active plan 可归档 |
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
| fullstack Delivery / Final Verification live 闭环 | 进行中(active train) | `docs/exec-plans/active/2026-07-19-fullstack-dogfood-016x-release-train.md` |
|
|
51
51
|
| Dynamic Workflow runtime limits 强执法、更广 profile | 设计输入 | `docs/design/dynamic-workflow-dag-engine-roadmap.md` |
|
|
52
52
|
| Loop 与 Dynamic Workflow 更深双向集成 / 自动恢复 | 设计输入 | 同上;当前已有基础 `workflow` action |
|
|
53
|
-
| Console Phase 4 General Operator Chat
|
|
53
|
+
| Console Phase 4 General Operator Chat | 规划 / 未实现 | Console design residual |
|
|
54
54
|
| Eval Lab auto-promote / RSI Level 1 产品声称 | **禁止**写成已交付 | Eval Lab design + active plan |
|
|
55
55
|
|
|
56
|
-
> 本地 Operator Console
|
|
56
|
+
> 本地 Operator Console 统一面(0.18.0)已发布:单仓库、loopback、随 `@tea-agent/loop-agent` 同包、canonical mutation 只经 sibling CLI,Inspect 复用 GET-only Observe read model。它不是远端 Web Console,也不能把多租户/云编排需求偷渡进本地 Console。
|
|
57
57
|
|
|
58
58
|
> 注意:`docs/design/dynamic-workflow-dag-engine-roadmap.md` 含 2026-07-04 历史叙述;文中凡把 Cursor 写成受治理 executor 或 `loop` 的 `cursor-fix` 动作,均为**历史叙述**,现状以 Pi-only + 显式 `cursor-prompt` sidecar 为准。
|
|
59
59
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Worker 与 Feature 架构
|
|
2
2
|
|
|
3
|
-
本页说明 `agent-worker` 如何通过冻结的已发布 `loop-agent` 子进程执行 DAG(不 in-process import runtime kernel),以及其上的产品线 read model:TaskSpec、Task Pool、Feature
|
|
3
|
+
本页说明 `agent-worker` 如何通过冻结的已发布 `loop-agent` 子进程执行 DAG(不 in-process import runtime kernel),以及其上的产品线 read model:TaskSpec、Task Pool、Feature 与统一 Operator Console(Operate + Inspect)。边界契约权威是 `runtime-boundaries.md` §Worker adapter。
|
|
4
4
|
|
|
5
|
-
**维护校准:2026-07-22 / `@tea-agent/loop-agent@0.
|
|
5
|
+
**维护校准:2026-07-22 / `@tea-agent/loop-agent@0.18.0`** — 统一 Operator Console(Operate + Inspect)已落地;细节以 `CHANGELOG.md` 与 active unify plan 为准。
|
|
6
6
|
|
|
7
7
|
## 核心事实:子进程,非 in-process
|
|
8
8
|
|
|
@@ -73,19 +73,19 @@ controller identity 与 DAG skill snapshot 是两个不同冻结层(前者跨
|
|
|
73
73
|
- Delivery / Closeout:clean Delivery HEAD 上生成 canonical QA/最终验证证据、Delivery Package、Acceptance Coverage、PR 草稿;Closeout 默认预览,显式 `--apply --owner` 才原子写回。
|
|
74
74
|
- 权威证据:`CHANGELOG.md [0.10.0]`、`docs/reports/feature/2026-07-12-m2-completion-audit.md`。
|
|
75
75
|
|
|
76
|
-
### Observe
|
|
76
|
+
### Inspect(Observe 只读 read model)
|
|
77
77
|
|
|
78
78
|
- 模块:`src/worker/observe/`、`src/worker/observability/{read-model,event-store}.ts`。
|
|
79
79
|
- 全局快照:`buildGlobalSnapshot({ repoRoot })`(`src/worker/observability/read-model.ts`),是 **derived** 视图,消费 `.harness/` 与 Task Pool 事实,**不**改变执行成败。
|
|
80
|
-
- Observe
|
|
81
|
-
-
|
|
80
|
+
- Observe read model 是本地只读 Inspect 能力;snapshot 投影失败返回安全错误摘要而非全零健康状态。
|
|
81
|
+
- `agent-worker console serve` 在同一进程挂载 `/inspect/` 与现有 GET `/api/**`;`/api/health` 返回 `OperatorSurfaceHealthV1`。兼容期独立 Observe `:8787` 保持旧 health DTO 与 GET-only 行为。
|
|
82
82
|
|
|
83
|
-
### Local Operator Console(Official,0.
|
|
83
|
+
### Local Operator Console(Official,0.18.0)
|
|
84
84
|
|
|
85
85
|
- 模块:`src/worker/console/`(loopback `serve|doctor`、operator API、Vite SPA)。
|
|
86
|
-
- **已发布能力**:Happy Path / Interview
|
|
87
|
-
-
|
|
88
|
-
- 写入路径仍只经 `LoopAgentClient` → 已发布 `loop-agent`(含 `task contract *` / DAG confirm-run
|
|
86
|
+
- **已发布能力**:Happy Path / Interview、Task Contract、SSE、同站 Inspect、Run/Recovery 紧凑检视与 recovery CTA 矩阵(无 Cancel / 无主 CTA「直接改代码」)。
|
|
87
|
+
- Inspect 仍复用唯一 Observe read model,GET-only;不复制 snapshot projector。
|
|
88
|
+
- 写入路径仍只经 `LoopAgentClient` → 已发布 `loop-agent`(含 `task contract *` / DAG confirm-run)。
|
|
89
89
|
- 证据:completed Console Phase 0.5 / 1–3;handoff `docs/reports/feature/2026-07-22-console-mvp-handoff.md`;ADR 0005。
|
|
90
90
|
|
|
91
91
|
## 版本化自举的 deterministic canary
|
|
@@ -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
|
-
|
|
5
|
+
供 `generate-backend-pytest-pi` 使用。该节点是 `executor: "pi"`、`role: "implementer"`、`toolProfile: "write"` 的受限 writer,只把已经通过 Markdown gate 的最终用例转换为 pytest 资产。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## 当前合同
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
81
|
-
def
|
|
82
|
-
|
|
83
|
-
|
|
16
|
+
class TestOrderApi:
|
|
17
|
+
def test_BE_ORDER_001_create_order(self) -> None:
|
|
18
|
+
"""BE-ORDER-001 创建合法订单。"""
|
|
19
|
+
...
|
|
84
20
|
```
|
|
85
21
|
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
28
|
+
## 推荐输出
|
|
197
29
|
|
|
198
|
-
|
|
30
|
+
写入文件后,用简短中文总结:
|
|
199
31
|
|
|
200
|
-
1.
|
|
201
|
-
2.
|
|
202
|
-
3.
|
|
203
|
-
4.
|
|
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
|
-
|
|
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": "
|
|
72
|
-
"HIGH": "gpt-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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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}\""
|