@tea-agent/loop-agent 0.16.25 → 0.17.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 (115) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +14 -3
  3. package/dist/cli/command-definitions.js +43 -0
  4. package/dist/cli/program.js +26 -0
  5. package/dist/commands/dag-approve.js +4 -0
  6. package/dist/commands/dag-resume.js +1 -0
  7. package/dist/commands/dag-validate.js +6 -0
  8. package/dist/commands/operator.js +44 -0
  9. package/dist/commands/task-contract.js +271 -0
  10. package/dist/executors/dag-pi-executor.js +118 -16
  11. package/dist/executors/pi-executor.js +206 -13
  12. package/dist/executors/pi-sdk-executor.js +21 -6
  13. package/dist/executors/shell-executor.js +85 -8
  14. package/dist/executors/shell-presets.js +16 -3
  15. package/dist/executors/shell-write-guard.js +64 -2
  16. package/dist/shared/operator/capabilities.js +255 -0
  17. package/dist/shared/operator/envelope.js +59 -0
  18. package/dist/shared/operator/index.js +4 -0
  19. package/dist/shared/operator/registry.js +38 -0
  20. package/dist/shared/operator/types.js +5 -0
  21. package/dist/task/contract/adopt.js +166 -0
  22. package/dist/task/contract/apply.js +326 -0
  23. package/dist/task/contract/canonicalize.js +60 -0
  24. package/dist/task/contract/constants.js +29 -0
  25. package/dist/task/contract/diff.js +177 -0
  26. package/dist/task/contract/hash.js +42 -0
  27. package/dist/task/contract/import-revision.js +96 -0
  28. package/dist/task/contract/index.js +17 -0
  29. package/dist/task/contract/journal.js +155 -0
  30. package/dist/task/contract/lock.js +153 -0
  31. package/dist/task/contract/observe.js +296 -0
  32. package/dist/task/contract/paths.js +19 -0
  33. package/dist/task/contract/project.js +170 -0
  34. package/dist/task/contract/recover.js +312 -0
  35. package/dist/task/contract/request-ledger.js +37 -0
  36. package/dist/task/contract/schema.js +151 -0
  37. package/dist/task/contract/transaction.js +160 -0
  38. package/dist/task/contract/types.js +1 -0
  39. package/dist/task/contract/validate-draft.js +106 -0
  40. package/dist/task/index.js +3 -0
  41. package/dist/task/operator/capabilities.js +6 -0
  42. package/dist/task/operator/envelope.js +2 -0
  43. package/dist/task/operator/index.js +5 -0
  44. package/dist/task/operator/registry.js +2 -0
  45. package/dist/task/operator/types.js +1 -0
  46. package/dist/task/runtime.js +5 -1
  47. package/dist/task/source-references.js +7 -0
  48. package/dist/worker/cli.js +150 -32
  49. package/dist/worker/console/app-data.js +185 -0
  50. package/dist/worker/console/dag-confirmation.js +313 -0
  51. package/dist/worker/console/doctor.js +169 -0
  52. package/dist/worker/console/draft-store.js +80 -0
  53. package/dist/worker/console/index.js +15 -0
  54. package/dist/worker/console/interview/assessment.js +67 -0
  55. package/dist/worker/console/interview/session.js +100 -0
  56. package/dist/worker/console/interview/tools.js +109 -0
  57. package/dist/worker/console/loopback.js +16 -0
  58. package/dist/worker/console/observe-health-match.js +174 -0
  59. package/dist/worker/console/observe-link.js +33 -0
  60. package/dist/worker/console/operation-runner.js +166 -0
  61. package/dist/worker/console/operation-sse.js +158 -0
  62. package/dist/worker/console/operation-store.js +147 -0
  63. package/dist/worker/console/operator-actions.js +769 -0
  64. package/dist/worker/console/pi-readiness.js +94 -0
  65. package/dist/worker/console/recovery-cta.js +133 -0
  66. package/dist/worker/console/repo-fingerprint.js +29 -0
  67. package/dist/worker/console/resource-loader.js +95 -0
  68. package/dist/worker/console/routes.js +368 -0
  69. package/dist/worker/console/security.js +126 -0
  70. package/dist/worker/console/server.js +149 -0
  71. package/dist/worker/console/sibling-controller.js +28 -0
  72. package/dist/worker/console/static/assets/index-CbnMgdWa.js +9 -0
  73. package/dist/worker/console/static/assets/index-Dnj0RVs8.css +1 -0
  74. package/dist/worker/console/static/index.html +13 -0
  75. package/dist/worker/console/vite.config.js +27 -0
  76. package/dist/worker/delivery/git-transaction.js +43 -8
  77. package/dist/worker/observe/health.js +57 -0
  78. package/dist/worker/observe/paths.js +81 -0
  79. package/dist/worker/observe/routes.js +142 -27
  80. package/dist/worker/observe/spec-evidence.js +84 -0
  81. package/dist/worker/observe/static/api.js +23 -0
  82. package/dist/worker/observe/static/state.js +26 -0
  83. package/dist/worker/observe/static/styles.css +10 -0
  84. package/dist/worker/observe/static/views/dag-inspector.js +173 -6
  85. package/dist/workflows/dag/backend-test-analysis-contract.js +34 -9
  86. package/dist/workflows/dag/dynamic-runtime/shared.js +1 -0
  87. package/dist/workflows/dag/frontend-repair.js +1 -10
  88. package/dist/workflows/dag/init-hybrid.js +372 -115
  89. package/dist/workflows/dag/node-execution.js +57 -6
  90. package/dist/workflows/dag/project-governance-context.js +508 -0
  91. package/dist/workflows/dag/prompt.js +46 -1
  92. package/dist/workflows/dag/retry-policy.js +16 -1
  93. package/dist/workflows/dag/runner.js +9 -0
  94. package/dist/workflows/dag/skill-snapshot.js +1 -0
  95. package/dist/workflows/dag/task-contract-binding.js +138 -0
  96. package/dist/workflows/dag/types.js +84 -10
  97. package/dist/workflows/dag/validate.js +53 -7
  98. package/docs/README.md +2 -0
  99. package/docs/architecture/evolution.md +2 -0
  100. package/docs/architecture/system-overview.md +6 -0
  101. package/docs/architecture/worker-and-feature.md +7 -0
  102. package/docs/templates/agent-dag.schema.json +64 -2
  103. package/docs/templates/agent-dag.supervised-implementation.json +1 -0
  104. package/docs/templates/backend-test-dag.classify.prompt.md +1 -1
  105. package/docs/templates/backend-test-dag.generate-pytest.prompt.md +5 -5
  106. package/docs/templates/backend-test-dag.json +26 -154
  107. package/docs/templates/backend-test-dag.retrospect.prompt.md +1 -1
  108. package/docs/templates/backend-test-dag.review-cases.prompt.md +2 -2
  109. package/package.json +8 -2
  110. package/skills/agent-worker/SKILL.md +1 -0
  111. package/skills/agent-worker/references/agent-worker-operator.md +3 -2
  112. package/skills/frontend-design-review/SKILL.md +25 -16
  113. package/skills/frontend-implementation/references/node-contracts.md +5 -5
  114. package/skills/loop-agent/references/command-reference.md +48 -1
  115. package/skills/loop-agent/references/hybrid-dag.md +4 -4
@@ -241,15 +241,68 @@
241
241
  }
242
242
  }
243
243
  },
244
+ "projectGovernanceGate": {
245
+ "type": "object",
246
+ "additionalProperties": false,
247
+ "required": ["contextPath"],
248
+ "properties": {
249
+ "contextPath": {
250
+ "const": ".runtime/project-governance-context.json",
251
+ "description": "Run-owned project governance context. When applicable=false the gate is a deterministic no-op; otherwise verdictGate remains authoritative."
252
+ }
253
+ }
254
+ },
244
255
  "requirementCoverageGate": {
245
256
  "type": "object", "additionalProperties": false,
246
257
  "required": ["fromNodeIds", "requiredIds"],
258
+ "allOf": [
259
+ {
260
+ "if": { "required": ["fallbackFromNodeIds"] },
261
+ "then": { "properties": { "fromNodeIds": { "maxItems": 1 } } }
262
+ }
263
+ ],
247
264
  "properties": {
248
265
  "fromNodeIds": { "type": "array", "minItems": 1, "items": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" } },
266
+ "fallbackFromNodeIds": {
267
+ "type": "array",
268
+ "minItems": 1,
269
+ "items": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
270
+ "description": "Optional effective-source fallbacks tried in order only when the single primary node output is absent. Each source must also appear in depends_on."
271
+ },
249
272
  "requiredIds": { "type": "array", "minItems": 1, "items": { "type": "string", "pattern": "^(?:REQ|BR|AC)-[A-Z0-9]+(?:-[A-Z0-9]+)*$" } },
250
273
  "label": { "type": "string", "minLength": 1 }
251
274
  }
252
275
  },
276
+ "jsonArtifactGate": {
277
+ "type": "object",
278
+ "additionalProperties": false,
279
+ "required": ["fromNodeId", "schemaId", "artifactName", "outputDir"],
280
+ "properties": {
281
+ "fromNodeId": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
282
+ "fallbackFromNodeIds": {
283
+ "type": "array",
284
+ "minItems": 1,
285
+ "items": { "type": "string", "pattern": "^[a-z][a-z0-9-]*$" },
286
+ "description": "Optional effective-source fallbacks tried in order only when the primary current-run node output is absent. Existing malformed or schema-invalid primary output fails closed. Each source must also appear in depends_on."
287
+ },
288
+ "schemaId": {
289
+ "enum": [
290
+ "backend-test-analysis-v1",
291
+ "backend-test-analysis-v2",
292
+ "backend-test-execution-v1",
293
+ "backend-test-result-v1",
294
+ "backend-test-classification-v1",
295
+ "backend-test-semantic-review-v1",
296
+ "backend-test-case-manifest-v1",
297
+ "frontend-implementation-contract-v1",
298
+ "frontend-test-result-v1"
299
+ ]
300
+ },
301
+ "artifactName": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*\\.json$" },
302
+ "outputDir": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" },
303
+ "junitRelativePath": { "type": "string", "minLength": 1 }
304
+ }
305
+ },
253
306
  "backendTestPipeline": {
254
307
  "enum": ["contracts", "semantic-initial", "execute-parse-initial", "classification-result-context"]
255
308
  },
@@ -270,6 +323,7 @@
270
323
  { "required": ["preset"] },
271
324
  { "required": ["verdictGate"] },
272
325
  { "required": ["requirementCoverageGate"] },
326
+ { "required": ["jsonArtifactGate"] },
273
327
  { "required": ["backendTestPipeline"] }
274
328
  ]
275
329
  },
@@ -308,10 +362,10 @@
308
362
  "retryCategories": {
309
363
  "type": "array",
310
364
  "items": {
311
- "enum": ["timeout", "network", "rate-limit", "unavailable"]
365
+ "enum": ["timeout", "network", "rate-limit", "unavailable", "output-too-large"]
312
366
  },
313
367
  "default": ["timeout", "network", "rate-limit", "unavailable"],
314
- "description": "Failure categories eligible for retry. quota is never eligible."
368
+ "description": "Failure categories eligible for retry. quota is never eligible. output-too-large is reserved for explicit structured-required nodes and is not part of the default retry set."
315
369
  }
316
370
  }
317
371
  },
@@ -370,6 +424,10 @@
370
424
  "items": { "type": "string", "minLength": 1 }
371
425
  },
372
426
  "toolProfile": { "$ref": "#/$defs/toolProfile" },
427
+ "governanceStandardReview": {
428
+ "type": "boolean",
429
+ "description": "Explicitly opts this node into writer-change-scoped AGENTS.md and repository-local code-standard review. Never inferred from node id or role."
430
+ },
373
431
  "writePolicy": { "$ref": "#/$defs/writePolicy" },
374
432
  "writeSet": {
375
433
  "type": "array",
@@ -389,6 +447,10 @@
389
447
  "type": "string",
390
448
  "minLength": 1
391
449
  },
450
+ "outputMode": {
451
+ "enum": ["default", "structured-required"],
452
+ "description": "Optional output semantics for Pi nodes. structured-required means oversized assistant output must not be accepted as a truncated success; eligible read-only nodes may compact-retry and downstream gates should rely on canonical structured artifacts."
453
+ },
392
454
  "firstProtocolLine": {
393
455
  "type": "string",
394
456
  "minLength": 1,
@@ -530,6 +530,7 @@
530
530
  "complexity": "HIGH",
531
531
  "executor": "pi",
532
532
  "role": "reviewer",
533
+ "governanceStandardReview": true,
533
534
  "writePolicy": "read-only",
534
535
  "allowedPaths": [
535
536
  "**"
@@ -71,5 +71,5 @@ Do **not** invent pass rates or failure lists from raw logs when Result v1 is pr
71
71
  ### Non-goals
72
72
 
73
73
  - Do not rewrite Result v1.
74
- - Do not decide final DAG success/failure (that is `backend-test-outcome-gate-shell`).
74
+ - Do not decide pipeline completion or L-5 readiness; classification is interpretive evidence only.
75
75
  - Do not implement M3 case manifest / Task Pool auto follow-up.
@@ -2,7 +2,7 @@
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 reviewed backend functional test cases into pytest automation code with 1:1 traceability.
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.
6
6
 
7
7
  Do **not** create a new executor type. This is a standard `executor: pi` writer node.
8
8
 
@@ -11,7 +11,7 @@ Do **not** create a new executor type. This is a standard `executor: pi` writer
11
11
  ```json
12
12
  {
13
13
  "id": "generate-backend-pytest-pi",
14
- "depends_on": ["review-backend-cases-gate-shell", "backend-test-execution-contract-shell"],
14
+ "depends_on": ["backend-test-case-manifest-shell", "validate-backend-test-contracts-shell"],
15
15
  "complexity": "HIGH",
16
16
  "executor": "pi",
17
17
  "role": "implementer",
@@ -38,12 +38,12 @@ Your job is to convert reviewed test cases under `testcase/md/` into pytest auto
38
38
 
39
39
  ### Inputs
40
40
 
41
- 1. **Reviewed test cases** — files under `testcase/md/` (approved by `review-backend-cases-pi` / `review-backend-cases-gate-shell`).
42
- 2. **Validated Backend Test Analysis v1** — run-owned `contracts/backend-test-analysis.json` from `backend-test-analysis-contract-shell`.
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
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
44
  4. **Target project conventions** — read `conftest.py`, `pytest.ini` / `pyproject.toml` to understand conventions, but do NOT modify them.
45
45
 
46
- Do NOT re-read source documents for free-form analysis. Use only reviewed cases and the validated contracts. Use only fixture/env/testRoot facts already present in the execution contract; never invent production credentials or secret values.
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
47
 
48
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
49
 
@@ -28,9 +28,10 @@
28
28
  "Root artifacts/ is reserved for explicit exclusive write nodes, not read-only scout/reviewer output",
29
29
  "exclusive implementer nodes must use narrow, concrete writeSet paths; never keep ** or repo root",
30
30
  "Replace REPLACE/WITH/NARROW/IMPLEMENT/PATHS/** with concrete paths before executing the implementation writer",
31
- "backend-test-dag uses exactly 16 real top-level tasks and executes pytest exactly once.",
32
- "Case and semantic request-revision verdicts fail at deterministic gates; no in-run revision or repair writer is authorized.",
33
- "Analysis, execution, manifest, semantic review, single-run result, classification, canonical result, retrospective and outcome evidence remain run-owned and fail-closed.",
31
+ "backend-test-dag uses exactly 12 real top-level tasks and executes pytest exactly once.",
32
+ "Case review is advisory evidence consumed by canonical context, retrospective, and L-5; it does not authorize or block the pytest writer.",
33
+ "Deterministic traceability is the only generated-asset hard gate before pytest.",
34
+ "Analysis, execution, manifest, case review, traceability, single-run result, classification, canonical context, retrospective and L-5 evidence remain run-owned and fail-closed.",
34
35
  "Functional test case IDs must use BE-<MODULE>-<NNN> format.",
35
36
  "pytest writers may only create the initially declared testcase assets; production code, config, skip/xfail, swallowed failures and mock substitution are forbidden."
36
37
  ],
@@ -68,8 +69,8 @@
68
69
  "executorModels": {
69
70
  "pi": {
70
71
  "LOW": "gpt-5.3-codex-spark",
71
- "MED": "grok-4.5",
72
- "HIGH": "gpt-5.6-sol"
72
+ "MED": "glm-5.2",
73
+ "HIGH": "gpt-5.5"
73
74
  }
74
75
  },
75
76
  "tasks": [
@@ -191,7 +192,8 @@
191
192
  "id": "review-backend-cases-pi",
192
193
  "depends_on": [
193
194
  "backend-test-case-manifest-shell",
194
- "validate-backend-test-contracts-shell"
195
+ "validate-backend-test-contracts-shell",
196
+ "generate-backend-pytest-pi"
195
197
  ],
196
198
  "role": "reviewer",
197
199
  "executor": "pi",
@@ -206,8 +208,8 @@
206
208
  ".harness/dag-runs/**",
207
209
  "artifacts/**"
208
210
  ],
209
- "outputContract": "Plain Markdown whose first non-empty line is VERDICT: pass or VERDICT: request-revision; followed by Findings and Coverage Assessment. No file writes. The deterministic gate accepts pass only; request-revision ends this run.",
210
- "subtask_prompt": "Review the generated backend functional test cases under testcase/md/ and the validated Case Manifest v1.\n\n## Mandatory First Line:\n\nFirst non-empty line must be exactly: VERDICT: pass or VERDICT: request-revision\n\n## Review Checklist:\n\n- ID format: every case uses BE-<MODULE>-<NNN> (full ids only in bodies and matrices)\n\n- Positive coverage: each in-scope acceptance criterion (AC-xxx) has happy-path case\n\n- Negative coverage: error scenarios (invalid input, not found, state violations)\n\n- Traceability: each explicit AC maps to a case ID or an evidenceGap in contracts/backend-test-case-manifest.json\n\n- Case structure: ID, Title, Precondition, Steps, Expected Result\n\n- No duplicate IDs across files\n\n- Manifest consistency (Critical): every AC claimed in MD case bodies/matrices must match manifest caseId→acIds; never accept 'all cases cover AC-xxx' unless every case maps that AC\n\n## Conditional Coverage (check ONLY if mentioned in upstream analysis):\n\n- Boundary coverage: check ONLY if analyze-inputs-pi mentions value ranges, length limits, numeric bounds, or format constraints\n\n- State transition coverage: check ONLY if analyze-inputs-pi mentions state machine\n\n- Authentication coverage: check ONLY if analyze-inputs-pi mentions auth mechanism\n\n- Timeout coverage: check ONLY if analyze-inputs-pi mentions timeout handling\n\n- Concurrency coverage: check ONLY if analyze-inputs-pi mentions concurrency/idempotency rules\n\n- If not mentioned, do NOT flag as missing\n\n## Do NOT treat as Critical alone:\n\n- Missing test_*.py / automation still planned (expected before generate-backend-pytest-pi)\n\n- Out-of-scope ACs already listed in manifest evidenceGaps (Flyway, frontend e2e, mvn test)\n\n## Verdict Rules:\n\n- All Critical checks pass + Important findings ≤ 2 → VERDICT: pass\n\n- Any Critical fails OR Important > 2 → VERDICT: request-revision\n\n- Any request-revision verdict ends the current run at the deterministic gate; describe findings clearly for an independent follow-up task.\n\n## Output After Verdict:\n\n1. Coverage Assessment table (AC → full BE-* case IDs) using manifest + MD\n\n2. Findings list (Critical/Important/Informational)\n\n3. Statistics (total cases, positive/negative/boundary breakdown)\n\n4. Required follow-up actions (only when request-revision; no in-run writer)\n\n## Constraints:\n\n- Read-only: do not modify files\n\n- Read validated analysis + case manifest artifacts; do not recompute coverage percentages\n\n- Use testcase/md/ files for case review",
211
+ "outputContract": "advisory case review evidence whose first non-empty line is VERDICT: pass or VERDICT: request-revision; followed by Findings and Coverage Assessment. No file writes; this review neither authorizes nor blocks pytest generation.",
212
+ "subtask_prompt": "Review the generated backend functional test cases under testcase/md/ and the validated Case Manifest v1.\n\n## Mandatory First Line:\n\nFirst non-empty line must be exactly: VERDICT: pass or VERDICT: request-revision\n\n## Review Checklist:\n\n- ID format: every case uses BE-<MODULE>-<NNN> (full ids only in bodies and matrices)\n\n- Positive coverage: each in-scope acceptance criterion (AC-xxx) has happy-path case\n\n- Negative coverage: error scenarios (invalid input, not found, state violations)\n\n- Traceability: each explicit AC maps to a case ID or an evidenceGap in contracts/backend-test-case-manifest.json\n\n- Case structure: ID, Title, Precondition, Steps, Expected Result\n\n- No duplicate IDs across files\n\n- Manifest consistency (Critical): every AC claimed in MD case bodies/matrices must match manifest caseId→acIds; never accept 'all cases cover AC-xxx' unless every case maps that AC\n\n## Conditional Coverage (check ONLY if mentioned in upstream analysis):\n\n- Boundary coverage: check ONLY if analyze-inputs-pi mentions value ranges, length limits, numeric bounds, or format constraints\n\n- State transition coverage: check ONLY if analyze-inputs-pi mentions state machine\n\n- Authentication coverage: check ONLY if analyze-inputs-pi mentions auth mechanism\n\n- Timeout coverage: check ONLY if analyze-inputs-pi mentions timeout handling\n\n- Concurrency coverage: check ONLY if analyze-inputs-pi mentions concurrency/idempotency rules\n\n- If not mentioned, do NOT flag as missing\n\n## Do NOT treat as Critical alone:\n\n- Missing test_*.py / automation still planned (expected before generate-backend-pytest-pi)\n\n- Out-of-scope ACs already listed in manifest evidenceGaps (Flyway, frontend e2e, mvn test)\n\n## Verdict Rules:\n\n- All Critical checks pass + Important findings ≤ 2 → VERDICT: pass\n\n- Any Critical fails OR Important > 2 → VERDICT: request-revision\n\n- Any request-revision verdict is advisory evidence for canonical context, retrospective, and L-5; it does not authorize or block the pytest writer.\n\n## Output After Verdict:\n\n1. Coverage Assessment table (AC → full BE-* case IDs) using manifest + MD\n\n2. Findings list (Critical/Important/Informational)\n\n3. Statistics (total cases, positive/negative/boundary breakdown)\n\n4. Required follow-up actions (only when request-revision; no in-run writer)\n\n## Constraints:\n\n- Read-only: do not modify files\n\n- Read validated analysis + case manifest artifacts; do not recompute coverage percentages\n\n- Use testcase/md/ files for case review",
211
213
  "retryPolicy": {
212
214
  "maxAttempts": 3,
213
215
  "backoff": "exponential",
@@ -221,44 +223,10 @@
221
223
  ]
222
224
  }
223
225
  },
224
- {
225
- "id": "review-backend-cases-gate-shell",
226
- "depends_on": [
227
- "review-backend-cases-pi"
228
- ],
229
- "role": "verifier",
230
- "executor": "shell",
231
- "complexity": "LOW",
232
- "writePolicy": "read-only",
233
- "allowedPaths": [
234
- "testcase/**",
235
- "docs/test-reports/**"
236
- ],
237
- "forbiddenPaths": [
238
- ".harness/**",
239
- ".harness/dag-runs/**",
240
- "artifacts/**"
241
- ],
242
- "outputContract": "Deterministic backend case review gate: exit 0 only when the first and only review emits VERDICT: pass.",
243
- "subtask_prompt": "Block pytest generation when backend case review requests revision; do not authorize an in-run writer.",
244
- "shell": {
245
- "commands": [],
246
- "verdictGate": {
247
- "fromNodeId": "review-backend-cases-pi",
248
- "accept": [
249
- "VERDICT: pass"
250
- ],
251
- "label": "backend case review",
252
- "lineMode": "first-verdict-line"
253
- },
254
- "cwd": ".",
255
- "timeoutMs": 60000
256
- }
257
- },
258
226
  {
259
227
  "id": "generate-backend-pytest-pi",
260
228
  "depends_on": [
261
- "review-backend-cases-gate-shell",
229
+ "backend-test-case-manifest-shell",
262
230
  "validate-backend-test-contracts-shell"
263
231
  ],
264
232
  "role": "implementer",
@@ -280,48 +248,15 @@
280
248
  ".harness/dag-runs/**",
281
249
  "artifacts/**"
282
250
  ],
283
- "subtask_prompt": "Convert the reviewed test cases under testcase/md/ into pytest automation code.\n\n\n\n## Inputs (MUST use validated contracts):\n\n- Reviewed cases under testcase/md/ (after review-backend-cases-gate-shell).\n\n- Validated Backend Test Analysis v1 under the current run contracts/ (analysis gate).\n\n- Validated Backend Test Execution Contract v1 under contracts/backend-test-execution.json (execution gate).\n\nUse only fixture names, env NAMES, testRoot, targetMode, and field/API facts already present in those contracts or reviewed cases. Do not invent production credentials or secret values.\n\nWhen targetMode is in-process (including demoted local npm/node managed servers): bootstrap the service inside function-scoped pytest fixtures under testcase/** — e.g. subprocess node server.js / startWelcomeServer with PORT=0 — and never require host-injected base URL env vars (clean-env shell will not provide WELCOME_BASE_URL / API_BASE_URL).\n\nDo not depend on requiredEnvNames being present at process start for in-process mode; if the contract still lists an env name, the fixture must set it or start the server without that env.\n\n\n\n## Output Steps (do in order):\n\n1. First, output a brief summary: how many files, how many test functions planned\n\n2. Then write each test file under testcase/\n\n\n\n## Format Rules:\n\n- File prefix: test_<module>.py\n\n- Function name: test_BE_<MODULE>_<NNN>_<description>\n\n- Docstring first line: BE-<MODULE>-<NNN>: <Case Title>\n\n- 1:1 mapping: each functional case → one pytest function\n\n\n\n## Implementation Rules:\n\n- Use assert statements, not unittest assertions\n\n- Use @pytest.mark.parametrize for boundary cases when the case defines edge values\n\n- Use markers: @pytest.mark.positive, @pytest.mark.negative, @pytest.mark.boundary\n\n\n\n## Test Data Preparation Rules (MUST follow):\n\n\n\n### When Setup is Needed\n\nSetup phase is REQUIRED only when test cases need pre-existing data:\n\n- Query/Read APIs: need data to exist before querying\n\n- Update/Delete APIs: need data to exist before modifying\n\n- State transition tests: need data in specific state\n\n\n\nSetup phase is NOT needed for:\n\n- Create APIs: testing the creation itself\n\n- Validation tests: testing input validation with invalid data\n\n\n\n### Data Setup Strategy\n\nWhen setup is needed:\n\n1. Prefer function-scoped fixtures for isolation; use module/session scope only when cases explicitly share immutable fixtures\n\n2. Prefer API-based setup from the upstream analyze-inputs-pi API list and reviewed cases\n\n3. If a required helper/factory is missing, create NEW files only under testcase/**/helpers/** or testcase/**/factories/**\n\n\n\n### Data Construction Priority\n\n1. API-first: construct data via documented APIs from analyze-inputs-pi / reviewed cases\n\n2. Reuse existing conftest fixtures when present (read-only)\n\n3. Direct DB writes are LAST RESORT and only if conftest already exposes a safe test DB fixture with rollback/isolation\n\n4. If neither API nor safe DB fixture exists, skip the case with an explicit gap note — do NOT invent production DB credentials or write live data\n\n\n\n### API Data Construction\n\n- Prefer the analyze-inputs-pi API Endpoints section and reviewed cases for method/path/fields\n\n- Chain API calls only when cases document multi-step preconditions\n\n- Store created resource IDs in fixtures for reuse\n\n- Do NOT broadly search host route/controller trees for secrets, .env, private keys, or production configs\n\n- Read host API definitions only when needed to resolve a field name already referenced by reviewed cases; stay out of credential/config paths\n\n\n\n### Database Data Construction (restricted)\n\n- Allowed only via existing conftest test-DB fixtures with transaction rollback or equivalent isolation\n\n- Never hardcode connection strings, passwords, tokens, or cloud credentials\n\n- Never target production/shared non-test databases\n\n- If isolation is unclear, report the gap instead of writing DB rows\n\n\n\n## Assertion Rules (MUST follow):\n\n\n\n### Positive Path\n\nMUST assert ALL of the following:\n\n1. HTTP status code: as defined in API spec (e.g. 200, 201)\n\n2. Response structure: key fields exist in response body\n\n3. Specific values: each field equals expected value from test case\n\n4. Data type: each field is correct type\n\n\n\n### Negative Path\n\nMUST assert ALL of the following:\n\n1. HTTP status code: as defined in API spec (e.g. 400, 404, 500)\n\n2. Error code field: field name from API spec (e.g. code, error_code, errcode, ret)\n\n3. Error message field: field name from API spec (e.g. message, msg, errmsg, error)\n\n\n\n### Field Name Resolution\n\nField names MUST come from the upstream analyze-inputs-pi output (API Endpoints section) or reviewed cases, NOT guessed. For example:\n\n- If API spec defines {\"ret\": 0, \"msg\": \"success\"}, assert response.json()['ret'] and response.json()['msg']\n\n- If API spec defines {\"code\": 4001, \"message\": \"error\"}, assert response.json()['code'] and response.json()['message']\n\n\n\n## Conditional Implementation (include ONLY if test cases exist):\n\n- Authentication tests: implement ONLY if testcase/md/ contains auth-related cases\n\n- Timeout tests: implement ONLY if testcase/md/ contains timeout-related cases\n\n- Boundary tests: implement ONLY when cases define value ranges, length limits, or format constraints\n\n- Use @pytest.mark.auth for auth tests, @pytest.mark.timeout for timeout tests\n\n- If no such cases exist, do NOT add these tests\n\n\n\n## Constraints:\n\n- Only create NEW files under writeSet: testcase/**/test_*.py, testcase/**/helpers/**, testcase/**/factories/**\n\n- Do NOT modify existing framework files (conftest.py, pytest.ini, pyproject.toml, setup.cfg, __init__.py)\n\n- If a test filename exists, add suffix: test_order.py → test_order_01.py\n\n- Do NOT re-read source documents — use reviewed cases under testcase/md/ and upstream analyze-inputs-pi output only\n\n- Read existing conftest.py/pytest.ini to understand conventions, but do NOT modify them\n\n- Do NOT execute pytest/python -m pytest or npm test in this node; the single execution is owned by the dedicated shell node. Local smoke runs create __pycache__/.pytest_cache and are unnecessary here."
251
+ "subtask_prompt": "Convert the validated test cases under testcase/md/ into pytest automation code.\n\n\n\n## Inputs (MUST use validated contracts):\n\n- Validated cases under testcase/md/ and contracts/backend-test-case-manifest.json (case review runs independently as advisory evidence).\n\n- Validated Backend Test Analysis v2 under contracts/backend-test-analysis.json.\n\n\n\n- Validated Backend Test Execution Contract v1 under contracts/backend-test-execution.json (execution gate).\n\nUse only fixture names, env NAMES, testRoot, targetMode, and field/API facts already present in those contracts or reviewed cases. Do not invent production credentials or secret values.\n\nWhen targetMode is in-process (including demoted local npm/node managed servers): bootstrap the service inside function-scoped pytest fixtures under testcase/** — e.g. subprocess node server.js / startWelcomeServer with PORT=0 — and never require host-injected base URL env vars (clean-env shell will not provide WELCOME_BASE_URL / API_BASE_URL).\n\nDo not depend on requiredEnvNames being present at process start for in-process mode; if the contract still lists an env name, the fixture must set it or start the server without that env.\n\n\n\n## Output Steps (do in order):\n\n1. First, output a brief summary: how many files, how many test functions planned\n\n2. Then write each test file under testcase/\n\n\n\n## Format Rules:\n\n- File prefix: test_<module>.py\n\n- Function name: test_BE_<MODULE>_<NNN>_<description>\n\n- Docstring first line: BE-<MODULE>-<NNN>: <Case Title>\n\n- 1:1 mapping: each functional case → one pytest function\n\n\n\n## Implementation Rules:\n\n- Use assert statements, not unittest assertions\n\n- Use @pytest.mark.parametrize for boundary cases when the case defines edge values\n\n- Use markers: @pytest.mark.positive, @pytest.mark.negative, @pytest.mark.boundary\n\n\n\n## Test Data Preparation Rules (MUST follow):\n\n\n\n### When Setup is Needed\n\nSetup phase is REQUIRED only when test cases need pre-existing data:\n\n- Query/Read APIs: need data to exist before querying\n\n- Update/Delete APIs: need data to exist before modifying\n\n- State transition tests: need data in specific state\n\n\n\nSetup phase is NOT needed for:\n\n- Create APIs: testing the creation itself\n\n- Validation tests: testing input validation with invalid data\n\n\n\n### Data Setup Strategy\n\nWhen setup is needed:\n\n1. Prefer function-scoped fixtures for isolation; use module/session scope only when cases explicitly share immutable fixtures\n\n2. Prefer API-based setup from the upstream analyze-inputs-pi API list and reviewed cases\n\n3. If a required helper/factory is missing, create NEW files only under testcase/**/helpers/** or testcase/**/factories/**\n\n\n\n### Data Construction Priority\n\n1. API-first: construct data via documented APIs from analyze-inputs-pi / reviewed cases\n\n2. Reuse existing conftest fixtures when present (read-only)\n\n3. Direct DB writes are LAST RESORT and only if conftest already exposes a safe test DB fixture with rollback/isolation\n\n4. If neither API nor safe DB fixture exists, skip the case with an explicit gap note — do NOT invent production DB credentials or write live data\n\n\n\n### API Data Construction\n\n- Prefer the analyze-inputs-pi API Endpoints section and reviewed cases for method/path/fields\n\n- Chain API calls only when cases document multi-step preconditions\n\n- Store created resource IDs in fixtures for reuse\n\n- Do NOT broadly search host route/controller trees for secrets, .env, private keys, or production configs\n\n- Read host API definitions only when needed to resolve a field name already referenced by reviewed cases; stay out of credential/config paths\n\n\n\n### Database Data Construction (restricted)\n\n- Allowed only via existing conftest test-DB fixtures with transaction rollback or equivalent isolation\n\n- Never hardcode connection strings, passwords, tokens, or cloud credentials\n\n- Never target production/shared non-test databases\n\n- If isolation is unclear, report the gap instead of writing DB rows\n\n\n\n## Assertion Rules (MUST follow):\n\n\n\n### Positive Path\n\nMUST assert ALL of the following:\n\n1. HTTP status code: as defined in API spec (e.g. 200, 201)\n\n2. Response structure: key fields exist in response body\n\n3. Specific values: each field equals expected value from test case\n\n4. Data type: each field is correct type\n\n\n\n### Negative Path\n\nMUST assert ALL of the following:\n\n1. HTTP status code: as defined in API spec (e.g. 400, 404, 500)\n\n2. Error code field: field name from API spec (e.g. code, error_code, errcode, ret)\n\n3. Error message field: field name from API spec (e.g. message, msg, errmsg, error)\n\n\n\n### Field Name Resolution\n\nField names MUST come from the upstream analyze-inputs-pi output (API Endpoints section) or reviewed cases, NOT guessed. For example:\n\n- If API spec defines {\"ret\": 0, \"msg\": \"success\"}, assert response.json()['ret'] and response.json()['msg']\n\n- If API spec defines {\"code\": 4001, \"message\": \"error\"}, assert response.json()['code'] and response.json()['message']\n\n\n\n## Conditional Implementation (include ONLY if test cases exist):\n\n- Authentication tests: implement ONLY if testcase/md/ contains auth-related cases\n\n- Timeout tests: implement ONLY if testcase/md/ contains timeout-related cases\n\n- Boundary tests: implement ONLY when cases define value ranges, length limits, or format constraints\n\n- Use @pytest.mark.auth for auth tests, @pytest.mark.timeout for timeout tests\n\n- If no such cases exist, do NOT add these tests\n\n\n\n## Constraints:\n\n- Only create NEW files under writeSet: testcase/**/test_*.py, testcase/**/helpers/**, testcase/**/factories/**\n\n- Do NOT modify existing framework files (conftest.py, pytest.ini, pyproject.toml, setup.cfg, __init__.py)\n\n- If a test filename exists, add suffix: test_order.py → test_order_01.py\n\n- Do NOT re-read source documents — use reviewed cases under testcase/md/ and upstream analyze-inputs-pi output only\n\n- Read existing conftest.py/pytest.ini to understand conventions, but do NOT modify them\n\n- Do NOT execute pytest/python -m pytest or npm test in this node; the single execution is owned by the dedicated shell node. Local smoke runs create __pycache__/.pytest_cache and are unnecessary here."
284
252
  },
285
253
  {
286
- "id": "review-generated-backend-pytest-pi",
254
+ "id": "backend-test-traceability-gate-shell",
287
255
  "depends_on": [
288
256
  "generate-backend-pytest-pi",
289
- "validate-backend-test-contracts-shell",
290
- "backend-test-case-manifest-shell"
291
- ],
292
- "role": "reviewer",
293
- "executor": "pi",
294
- "complexity": "MED",
295
- "writePolicy": "read-only",
296
- "allowedPaths": [
297
- "testcase/**"
298
- ],
299
- "forbiddenPaths": [
300
- ".harness/**",
301
- ".harness/dag-runs/**",
302
- "artifacts/**"
303
- ],
304
- "outputContract": "Pure Backend Test Semantic Review v1 JSON: verdict, findings[], summary. No file writes.",
305
- "subtask_prompt": "Review generated pytest semantics before the single execution.\n\nUse only compact authoritative inputs: contracts/backend-test-analysis.json, contracts/backend-test-case-manifest.json, testcase/md/**, and generated testcase/**/test_*.py/helpers/factories.\n\nReturn exactly one pure JSON object with only verdict, findings, summary; no Markdown fence or surrounding prose.\n\nverdict must be pass or request-revision. Each findings[] item must contain exactly severity, caseId, testFile, testSymbol, contractRefs, issue, requiredChange.\n\nseverity must be exactly Critical, Important, or Informational; contractRefs must be a non-empty string array. A request-revision verdict requires at least one finding; pass must not contain Critical findings.\n\nMinimal shape: {\"verdict\":\"pass\",\"findings\":[],\"summary\":\"No contract-backed semantic contradiction found.\"}\n\nCheck responseBody.kind (array vs object/items), ordering, field comparison (especially parseable-only date-time precision), documented status/error fields, and each caseId→symbol assertion meaning.\n\nDo not use aliases such as file, symbol, refs, finding, or requiredFix; the strict contract requires testFile, testSymbol, contractRefs, issue, requiredChange.\n\nrequest-revision only for concrete semantic contradiction with reviewed cases/formal analysis evidence. No style findings.\n\nRead-only; do not edit tests or production code.",
306
- "retryPolicy": {
307
- "maxAttempts": 3,
308
- "backoff": "exponential",
309
- "initialDelayMs": 2000,
310
- "maxDelayMs": 30000,
311
- "retryCategories": [
312
- "timeout",
313
- "network",
314
- "rate-limit",
315
- "unavailable"
316
- ]
317
- }
318
- },
319
- {
320
- "id": "validate-semantic-review-and-traceability-shell",
321
- "depends_on": [
322
- "review-generated-backend-pytest-pi",
323
257
  "backend-test-case-manifest-shell"
324
258
  ],
259
+ "dependsPolicy": "all-or-condition-skip",
325
260
  "role": "verifier",
326
261
  "executor": "shell",
327
262
  "complexity": "LOW",
@@ -335,39 +270,12 @@
335
270
  ".harness/dag-runs/**",
336
271
  "artifacts/**"
337
272
  ],
338
- "outputContract": "Materialize the only semantic review and validate pytest traceability.",
339
- "subtask_prompt": "Materialize semantic facts and traceability; verdict authorization is handled by the next deterministic gate.",
273
+ "outputContract": "Deterministic traceability: generated cases have real file/symbol; skipped/unsupported have gapReason; convention symbols scanned under testcase/**/test_*.py.",
274
+ "subtask_prompt": "Fail closed when generated automation claims do not resolve to workspace pytest symbols, or skip/unsupported lacks gapReason.",
340
275
  "shell": {
341
- "commands": [],
342
- "backendTestPipeline": "semantic-initial",
343
- "cwd": ".",
344
- "timeoutMs": 60000
345
- }
346
- },
347
- {
348
- "id": "backend-test-semantic-gate-shell",
349
- "depends_on": [
350
- "validate-semantic-review-and-traceability-shell",
351
- "review-generated-backend-pytest-pi"
352
- ],
353
- "role": "verifier",
354
- "executor": "shell",
355
- "complexity": "LOW",
356
- "writePolicy": "read-only",
357
- "allowedPaths": [
358
- "testcase/**",
359
- "docs/test-reports/**"
360
- ],
361
- "forbiddenPaths": [
362
- ".harness/**",
363
- ".harness/dag-runs/**",
364
- "artifacts/**"
365
- ],
366
- "outputContract": "Pass-only authorization by reading contracts/backend-test-semantic-review.json; only verdict=pass proceeds to the single pytest execution.",
367
- "subtask_prompt": "Read the canonical semantic review artifact written by validate-semantic-review-and-traceability-shell. Authorize only when verdict is pass. Do not materialize, do not parse raw Pi Markdown or VERDICT lines, and do not authorize an in-run pytest writer.",
368
- "shell": {
369
- "commands": [],
370
- "backendTestPipeline": "semantic-initial",
276
+ "commands": [
277
+ "backend-test-traceability-gate"
278
+ ],
371
279
  "cwd": ".",
372
280
  "timeoutMs": 60000
373
281
  }
@@ -375,7 +283,7 @@
375
283
  {
376
284
  "id": "execute-and-parse-backend-pytest-shell",
377
285
  "depends_on": [
378
- "backend-test-semantic-gate-shell",
286
+ "backend-test-traceability-gate-shell",
379
287
  "validate-backend-test-contracts-shell"
380
288
  ],
381
289
  "role": "verifier",
@@ -450,7 +358,9 @@
450
358
  "id": "materialize-classification-and-result-context-shell",
451
359
  "depends_on": [
452
360
  "classify-backend-test-result-pi",
453
- "backend-test-case-manifest-shell"
361
+ "backend-test-case-manifest-shell",
362
+ "review-backend-cases-pi",
363
+ "backend-test-traceability-gate-shell"
454
364
  ],
455
365
  "role": "verifier",
456
366
  "executor": "shell",
@@ -465,8 +375,8 @@
465
375
  ".harness/dag-runs/**",
466
376
  "artifacts/**"
467
377
  ],
468
- "outputContract": "Materialize Classification v1, copy the unique initial Result to canonical contracts/backend-test-result.json, and emit Result + Manifest + Classification context.",
469
- "subtask_prompt": "Validate classification and materialize canonical single-run result context without repair eligibility or rerun.",
378
+ "outputContract": "Materialize Classification v1, copy the unique initial Result to canonical contracts/backend-test-result.json, and emit Result + Manifest + Classification + advisory case review + traceability context.",
379
+ "subtask_prompt": "Validate classification and materialize canonical single-run result context with auditable case review and traceability evidence, without repair eligibility or rerun.",
470
380
  "shell": {
471
381
  "commands": [],
472
382
  "backendTestPipeline": "classification-result-context",
@@ -496,7 +406,7 @@
496
406
  "artifacts/**"
497
407
  ],
498
408
  "outputContract": "Maturity rating in assistant output plus a report written under docs/test-reports/**.",
499
- "subtask_prompt": "Read the complete JSON from direct upstream materialize-classification-and-result-context-shell and generate a test retrospective report.\n\nThat JSON contains result, manifest (including coverageSummary), and classification. Treat those fields as authoritative; do not rely on pointer/hash summaries.\n\n\n\n## Output Steps (do in order):\n\n1. First, output the maturity rating on the first line: Rating: A/B/C/D\n\n2. Then write the full report under docs/test-reports/\n\n\n\n## Stats authority (deterministic only):\n\n- Pass rate, failed/error/skipped counts, and failure list MUST come from contracts/backend-test-result.json only.\n\n- AC coverage ratio / case counts MUST come from contracts/backend-test-case-manifest.json coverageSummary (or gate-derived fields). Do NOT invent coverage %.\n\n- Automation coverage MUST use coverageSummary.generatedCount / coverageSummary.caseCount. If either field is missing, write unavailable; do not estimate.\n\n- Code coverage MUST come only from the validated contracts/code-coverage-v1.json artifact generated by coverage.py/pytest-cov or JaCoCo. Show line, branch, function/method, covered, total, ratio, threshold, status, source scope, requirement IDs, tool, commit, and artifact hash.\n\n- Stability MUST come from independent Stability Evidence: use successfulRuns / recordedRuns, same suite/version, and require n≥5; a single run is unavailable.\n\n- Use classify-backend-test-result-pi JSON as interpretive evidence only.\n\n- NEVER rewrite a failed result as passed. Outcome gate (not this report) is authoritative for task success.\n\n\n\n## Report Structure:\n\n1. Maturity Rating with rationale\n\n2. Test Coverage Summary (Result v1 pass rate, AC coverage, automation coverage, code coverage, and stability evidence)\n\n3. Failed Test Analysis (failure/error details, category, confidence, evidence, and owner direction)\n\n4. Defects (local Bug ledger in the same report directory; unavailable when absent)\n\n5. Risks (Critical/High/Medium/Low, impact, controls, residual risk, treatment; Critical risks block L-5, High risks do not automatically block)\n\n6. Regression Recommendations (immediate, related, periodic, deferred; every item links to failure/risk/AC/case IDs)\n\n7. L-5 conclusion with blocking items\n\n\n\n## Rating Criteria:\n\n- L-5 ready requires pass rate=100%, AC coverage=100%, automation coverage≥90%, stability≥95% with n≥5, line coverage≥80%, branch coverage≥70%, skipped=0, and no blocking Critical risk.\n\n- Any required metric fail or unavailable means L-5 not-ready. Function/method coverage is displayed but not a gate. Preserve the existing A/B/C/D single-run rating separately.\n\n\n\n## Constraints:\n\n- Stay within writeSet: docs/test-reports/**\n\n- Do NOT re-read source documents — use upstream outputs only\n\n- Do not write root artifacts/**"
409
+ "subtask_prompt": "Read the complete JSON from direct upstream materialize-classification-and-result-context-shell and generate a test retrospective report.\n\nThat JSON contains result, manifest (including coverageSummary), and classification. Treat those fields as authoritative; do not rely on pointer/hash summaries.\n\n\n\n## Output Steps (do in order):\n\n1. First, output the maturity rating on the first line: Rating: A/B/C/D\n\n2. Then write the full report under docs/test-reports/\n\n\n\n## Stats authority (deterministic only):\n\n- Pass rate, failed/error/skipped counts, and failure list MUST come from contracts/backend-test-result.json only.\n\n- AC coverage ratio / case counts MUST come from contracts/backend-test-case-manifest.json coverageSummary (or gate-derived fields). Do NOT invent coverage %.\n\n- Automation coverage MUST use coverageSummary.generatedCount / coverageSummary.caseCount. If either field is missing, write unavailable; do not estimate.\n\n- Code coverage MUST come only from the validated contracts/code-coverage-v1.json artifact generated by coverage.py/pytest-cov or JaCoCo. Show line, branch, function/method, covered, total, ratio, threshold, status, source scope, requirement IDs, tool, commit, and artifact hash.\n\n- Stability MUST come from independent Stability Evidence: use successfulRuns / recordedRuns, same suite/version, and require n≥5; a single run is unavailable.\n\n- Use classify-backend-test-result-pi JSON as interpretive evidence only.\n\n- NEVER rewrite a failed result as passed. Result v1 is authoritative for testOutcome; pipeline completion and L-5 readiness are separate conclusions.\n\n\n\n\n\n## Report Structure:\n\n1. Maturity Rating with rationale\n\n2. Test Coverage Summary (Result v1 pass rate, AC coverage, automation coverage, code coverage, and stability evidence)\n\n3. Failed Test Analysis (failure/error details, category, confidence, evidence, and owner direction)\n\n4. Defects (local Bug ledger in the same report directory; unavailable when absent)\n\n5. Risks (Critical/High/Medium/Low, impact, controls, residual risk, treatment; Critical risks block L-5, High risks do not automatically block)\n\n6. Regression Recommendations (immediate, related, periodic, deferred; every item links to failure/risk/AC/case IDs)\n\n7. L-5 conclusion with blocking items\n\n\n\n## Rating Criteria:\n\n- L-5 ready requires pass rate=100%, AC coverage=100%, automation coverage≥90%, stability≥95% with n≥5, line coverage≥80%, branch coverage≥70%, skipped=0, and no blocking Critical risk.\n\n- Any required metric fail or unavailable means L-5 not-ready. Function/method coverage is displayed but not a gate. Preserve the existing A/B/C/D single-run rating separately.\n\n\n\n## Constraints:\n\n- Stay within writeSet: docs/test-reports/**\n\n- Do NOT re-read source documents — use upstream outputs only\n\n- Do not write root artifacts/**"
500
410
  },
501
411
  {
502
412
  "id": "l5-metrics-pi",
@@ -530,44 +440,6 @@
530
440
  "unavailable"
531
441
  ]
532
442
  }
533
- },
534
- {
535
- "id": "backend-test-outcome-gate-shell",
536
- "depends_on": [
537
- "l5-metrics-pi"
538
- ],
539
- "role": "verifier",
540
- "executor": "shell",
541
- "complexity": "LOW",
542
- "writePolicy": "read-only",
543
- "allowedPaths": [
544
- "testcase/**",
545
- "docs/test-reports/**"
546
- ],
547
- "forbiddenPaths": [
548
- ".harness/**",
549
- ".harness/dag-runs/**",
550
- "artifacts/**"
551
- ],
552
- "outputContract": "Shell exit 0 only when Result v1 outcome=passed with failed=0 and error=0; non-zero otherwise. Ignores retrospective Markdown.",
553
- "subtask_prompt": "Gate the backend-test DAG on run-owned Result v1 shell facts only (not retrospective prose).",
554
- "shell": {
555
- "commands": [
556
- "test -n \"${HARNESS_DAG_RUN_DIR:-}\" || { echo \"missing HARNESS_DAG_RUN_DIR for backend-test outcome gate\" >&2; exit 2; }; RESULT=\"${HARNESS_DAG_RUN_DIR}/contracts/backend-test-result.json\"; test -f \"${RESULT}\" || { echo \"missing backend-test result: ${RESULT}\" >&2; exit 2; }; node -e 'const fs=require(\"fs\");const r=JSON.parse(fs.readFileSync(process.argv[1],\"utf8\"));const outcome=String(r.outcome||\"\");const ok=outcome===\"passed\"&&Number(r.failed||0)===0&&Number(r.error||0)===0;console.log(\"backend-test outcome=\"+outcome+\" passed=\"+r.passed+\" failed=\"+r.failed+\" error=\"+r.error+\" executionStatus=\"+r.executionStatus);if(!ok){process.exit(1);}' \"${RESULT}\""
557
- ],
558
- "verifyEvidence": {
559
- "phase": "final",
560
- "quota": "full",
561
- "commandSource": "inline",
562
- "commandCount": 1,
563
- "commandLabels": [
564
- "test -n \"${HARNESS_DAG_RUN_DIR:-}\" || { echo \"missing HARNESS_DAG_RUN_DIR for backend-test outcome gate\" >&2; exit 2; }; RESULT=\"${HARNESS_DAG_RUN_DIR}/contracts/backend-test-result.json\"; test -f \"${RESULT}\" || { echo \"missing backend-test result: ${RESULT}\" >&2; exit 2; }; node -e 'const fs=require(\"fs\");const r=JSON.parse(fs.readFileSync(process.argv[1],\"utf8\"));const outcome=String(r.outcome||\"\");const ok=outcome===\"passed\"&&Number(r.failed||0)===0&&Number(r.error||0)===0;console.log(\"backend-test outcome=\"+outcome+\" passed=\"+r.passed+\" failed=\"+r.failed+\" error=\"+r.error+\" executionStatus=\"+r.executionStatus);if(!ok){process.exit(1);}' \"${RESULT}\""
565
- ],
566
- "finalFullRequired": true
567
- },
568
- "cwd": ".",
569
- "timeoutMs": 60000
570
- }
571
443
  }
572
444
  ],
573
445
  "sourceBinding": {
@@ -31,7 +31,7 @@ You are the Backend Test DAG **test retrospective** agent.
31
31
 
32
32
  Your job is to read upstream Result v1 + classification (+ review report) and generate a retrospective report with a maturity rating. Write the report under `docs/test-reports/` only. Stay within `writeSet`. Do not write root `artifacts/**`.
33
33
 
34
- This node runs on **both pass and assertion-fail** paths (after parse + classify). Final task success is decided later by `backend-test-outcome-gate-shell` using Result v1 shell facts only **never** rewrite a failed result as passed in this report.
34
+ This node runs on **both pass and assertion-fail** paths after canonical context. Treat Result v1 as the sole testOutcome authority; pipeline completion and L-5 readiness are separate conclusions. **Never** rewrite a failed result as passed in this report. The context also carries advisory case review and deterministic traceability evidence, which must be reflected in the retrospective.
35
35
 
36
36
  ### Output Steps (do in order)
37
37
 
@@ -2,7 +2,7 @@
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. `VERDICT: request-revision` causes the deterministic `review-backend-cases-gate-shell` to fail; it does not authorize another writer in the same run.
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.
6
6
 
7
7
  Do **not** create `executor: reviewer`. Reviewer is a **role** on `executor: pi`.
8
8
 
@@ -86,4 +86,4 @@ Do NOT re-read source documents. Use the validated analysis artifact, case manif
86
86
 
87
87
  ### Fail-fast note
88
88
 
89
- There is no final review or in-run revision writer. Any `request-revision` verdict ends the current backend-test run at the deterministic case gate.
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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tea-agent/loop-agent",
3
- "version": "0.16.25",
3
+ "version": "0.17.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "loop-agent": "bin/loop-agent.js",
@@ -44,7 +44,8 @@
44
44
  "cursor": "node --import tsx/esm src/cli.ts cursor-prompt",
45
45
  "pi-prompt": "node --import tsx/esm src/cli.ts pi-prompt",
46
46
  "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
47
- "build": "npm run clean && tsc -p tsconfig.build.json && node -e \"const fs=require('node:fs');const p='dist/worker/observe/static';fs.mkdirSync(p,{recursive:true});fs.cpSync('src/worker/observe/static',p,{recursive:true});\"",
47
+ "build": "npm run clean && tsc -p tsconfig.build.json && node -e \"const fs=require('node:fs');const p='dist/worker/observe/static';fs.mkdirSync(p,{recursive:true});fs.cpSync('src/worker/observe/static',p,{recursive:true});\" && npm run console:build",
48
+ "console:build": "vite build --config src/worker/console/vite.config.ts",
48
49
  "prepack": "npm run build",
49
50
  "prepublishOnly": "node scripts/check-npm-publish-policy.mjs && npm run typecheck && npm test && npm run build",
50
51
  "lint": "tsc --noEmit",
@@ -71,9 +72,14 @@
71
72
  },
72
73
  "devDependencies": {
73
74
  "@types/node": "^24.6.0",
75
+ "@types/react": "^19.1.8",
76
+ "@types/react-dom": "^19.1.6",
74
77
  "@types/semver": "^7.7.1",
78
+ "react": "^19.1.0",
79
+ "react-dom": "^19.1.0",
75
80
  "tsx": "^4.20.6",
76
81
  "typescript": "^5.9.3",
82
+ "vite": "^7.0.0",
77
83
  "vitest": "^3.2.4"
78
84
  }
79
85
  }
@@ -16,6 +16,7 @@ references:
16
16
  - **允许**:`agent-worker` / `loop-agent` CLI;只读 `pool doctor`、`observe`、status/report;冻结 controller identity;选择 Ready 工作与 recovery 命令。
17
17
  - **禁止**:绕过 CLI 直接 Edit 业务实现;Worker/DAG 失败后主会话「救火改文件」。
18
18
  - **失败时只允许**:保留 evidence → `task retry` / `task reconcile` / `pool mark-failed` / human gate → 再经 CLI 重跑;实现写入仍只经 published `loop-agent` DAG。
19
+ - **Official vs Compatibility**:`agent-worker console serve` 是 Official 本地控制面;openCode 等主会话仍是 Compatibility Assist,二者**不是**同等保证。Console 与 Observe 分进程;深链依赖 Observe health match,Console 不 proxy Observe。
19
20
 
20
21
  ## Route the Work
21
22
 
@@ -7,7 +7,7 @@
7
7
  主会话使用本 reference 时是 **operator**,不是 implementer:
8
8
 
9
9
  | 允许 | 禁止 |
10
- |---|---|
10
+ | --- | --- |
11
11
  | `agent-worker` / `loop-agent` CLI | 宿主 Edit/Write 直接改业务实现 |
12
12
  | 只读 doctor / observe / report / status | Worker 或 DAG 失败后「救火改文件」 |
13
13
  | 冻结 controller identity、选 Ready、retry/reconcile | 跳过 published controller 手写实现收尾 |
@@ -52,7 +52,8 @@ Leaf DAG nodes 不得递归启动 `agent-worker`。Worker 负责 DAG 之外的 s
52
52
  ```
53
53
 
54
54
  doctor 只读;migrate 默认零写入,apply 失败全回滚且不改 JSONL。
55
- 8. Observe(`observe serve|snapshot`)只读;canonical Task 路由为 `/api/features/:featureId/tasks/:taskId` 与 `#/feature/:featureId/task/:taskId`。
55
+ 8. Observe(`observe serve|snapshot`)只读;canonical Task 路由为 `/api/features/:featureId/tasks/:taskId` 与 `#/feature/:featureId/task/:taskId`。`GET /api/health` 为 versioned DTO(fingerprint + routeCapabilities)。Console `observeLink` 仅 match 后深链;offline 展示 `agent-worker observe serve --repo . --port 8787`。
56
+ 9. Official Console:`agent-worker console serve|doctor`(loopback)。Recovery CTA 为 report/doctor/decision/resume/reconcile/regenerate;无 Cancel、无主 CTA「直接改代码」。主会话 Compatibility Assist 不得替代 Console/CLI 执法。
56
57
 
57
58
  ## Versioned Self-Hosting
58
59