@tea-agent/loop-agent 0.16.3 → 0.16.4

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/CHANGELOG.md CHANGED
@@ -15,6 +15,12 @@
15
15
  - Pi SDK 执行长推理或大段结构化输出时不再把高频流式增量事件无界累积到内存;同一响应在多个生命周期事件中重复出现的 Token 用量只统计一次,避免 `Invalid string length` 和成本数据虚高。
16
16
  - 后端测试复合执行节点继续保持 clean environment、失败分类和 fail-closed outcome,并为 initial/final Result、repair eligibility、traceability 与 Observe 投影保留结构化运行证据。
17
17
 
18
+ ## [0.16.4] - 2026-07-19
19
+
20
+ ### 修复
21
+
22
+ - 后端测试 `backend-test-semantic-final-gate-shell` 改为复合 pipeline `semantic-effective`,不再手写读 contracts 的 inline shell,避免 `--strict-governance` 误判为 fragile verdict gate 并阻断 BE-TEST DAG 校验。
23
+
18
24
  ## [0.16.3] - 2026-07-19
19
25
 
20
26
  ### 修复
@@ -334,6 +334,20 @@ async function executeBackendTestPipeline(input, meta) {
334
334
  throw new Error("backend pytest semantic review did not pass");
335
335
  }
336
336
  }
337
+ else if (pipeline === "semantic-effective") {
338
+ // Prefer final review contract when revision ran; otherwise accept initial pass.
339
+ const finalPath = path.join(meta.runDir, "contracts", "backend-test-semantic-review-final.json");
340
+ const initialPath = path.join(meta.runDir, "contracts", "backend-test-semantic-review.json");
341
+ const chosen = existsSync(finalPath) ? finalPath : initialPath;
342
+ if (!existsSync(chosen)) {
343
+ throw new Error("missing backend-test semantic review contract for effective gate");
344
+ }
345
+ const parsed = JSON.parse(await readFile(chosen, "utf8"));
346
+ if (parsed.verdict !== "pass") {
347
+ throw new Error("backend pytest semantic review did not pass");
348
+ }
349
+ outputs.push(`semantic=${chosen}`, `verdict=${parsed.verdict}`);
350
+ }
337
351
  else if (pipeline === "execute-parse-initial") {
338
352
  const results = await executePipelineCommands(input, meta);
339
353
  if (!results.every((result) => result.ok)) {
@@ -3128,10 +3128,8 @@ function buildBackendTestSemanticFinalGateNode(sources) {
3128
3128
  outputContract: "Pass-only semantic authorization for traceability and initial pytest.",
3129
3129
  subtask_prompt: "Accept initial pass path or final semantic review pass; fail closed otherwise.",
3130
3130
  shell: {
3131
- commands: [[
3132
- 'test -n "${HARNESS_DAG_RUN_DIR:-}" || exit 2',
3133
- 'node -e \'const fs=require("fs"),path=require("path");const r=process.env.HARNESS_DAG_RUN_DIR;const final=path.join(r,"contracts","backend-test-semantic-review-final.json");const first=path.join(r,"contracts","backend-test-semantic-review.json");const p=fs.existsSync(final)?final:first;const v=JSON.parse(fs.readFileSync(p,"utf8"));if(v.verdict!=="pass")throw new Error("backend pytest semantic review did not pass");console.log("backend pytest semantic gate: pass");\'',
3134
- ].join("; ")],
3131
+ commands: [],
3132
+ backendTestPipeline: "semantic-effective",
3135
3133
  cwd: ".",
3136
3134
  timeoutMs: 60000,
3137
3135
  },
@@ -3566,9 +3564,26 @@ function buildBackendTestHybridDag(sources) {
3566
3564
  revisePytest.runIf = "$.nodes['validate-semantic-review-and-traceability-shell'].json.verdict == 'request-revision'";
3567
3565
  const finalSemanticReview = buildBackendTestSemanticReviewNode(sources, { id: "review-generated-backend-pytest-final-pi", dependsOn: [revisePytest.id], final: true });
3568
3566
  finalSemanticReview.runIf = revisePytest.runIf;
3569
- const semanticFinal = { id: "backend-test-semantic-final-gate-shell", depends_on: [semanticInitial.id, finalSemanticReview.id], dependsPolicy: "all-or-condition-skip", role: "verifier", executor: "shell", complexity: "LOW", writePolicy: "read-only", allowedPaths: commonReadOnlyPaths(sources), forbiddenPaths: commonForbiddenPaths(sources), outputContract: "Pass-only effective semantic review gate with final traceability after revision.", subtask_prompt: "Accept initial semantic pass or validate the single final review and traceability.", shell: { commands: [['test -n "${HARNESS_DAG_RUN_DIR:-}" || exit 2', 'node -e \'const fs=require("fs"),path=require("path");const r=process.env.HARNESS_DAG_RUN_DIR;const f=path.join(r,"contracts","backend-test-semantic-review-final.json");const i=path.join(r,"contracts","backend-test-semantic-review.json");const v=JSON.parse(fs.readFileSync(fs.existsSync(f)?f:i,"utf8"));if(v.verdict!=="pass")throw new Error("backend pytest semantic review did not pass");\''].join("; ")], cwd: ".", timeoutMs: 60000 } };
3570
3567
  const finalSemanticMaterialize = { id: "materialize-final-semantic-review-shell", depends_on: [finalSemanticReview.id], role: "verifier", executor: "shell", complexity: "LOW", writePolicy: "read-only", allowedPaths: commonReadOnlyPaths(sources), forbiddenPaths: commonForbiddenPaths(sources), runIf: revisePytest.runIf, outputContract: "Materialize final semantic review and re-check traceability.", subtask_prompt: "Validate final semantic review and traceability.", shell: { commands: [], backendTestPipeline: "semantic-final", cwd: ".", timeoutMs: 60000 } };
3571
- semanticFinal.depends_on = [semanticInitial.id, finalSemanticMaterialize.id];
3568
+ const semanticFinal = {
3569
+ id: "backend-test-semantic-final-gate-shell",
3570
+ depends_on: [semanticInitial.id, finalSemanticMaterialize.id],
3571
+ dependsPolicy: "all-or-condition-skip",
3572
+ role: "verifier",
3573
+ executor: "shell",
3574
+ complexity: "LOW",
3575
+ writePolicy: "read-only",
3576
+ allowedPaths: commonReadOnlyPaths(sources),
3577
+ forbiddenPaths: commonForbiddenPaths(sources),
3578
+ outputContract: "Pass-only effective semantic review gate with final traceability after revision.",
3579
+ subtask_prompt: "Accept initial semantic pass or validate the single final review and traceability.",
3580
+ shell: {
3581
+ commands: [],
3582
+ backendTestPipeline: "semantic-effective",
3583
+ cwd: ".",
3584
+ timeoutMs: 60000,
3585
+ },
3586
+ };
3572
3587
  const executeInitial = buildExecuteBackendPytestNode(sources, { id: "execute-and-parse-backend-pytest-initial-shell", dependsOn: [semanticFinal.id, contracts.id], reportStem: "backend-test-initial" });
3573
3588
  executeInitial.shell.backendTestPipeline = "execute-parse-initial";
3574
3589
  const classify = buildClassifyBackendTestResultNode(sources);
@@ -145,6 +145,7 @@ export const dagBackendTestPipelineSchema = z.enum([
145
145
  "contracts",
146
146
  "semantic-initial",
147
147
  "semantic-final",
148
+ "semantic-effective",
148
149
  "execute-parse-initial",
149
150
  "classification-eligibility",
150
151
  "repair-safety-traceability",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tea-agent/loop-agent",
3
- "version": "0.16.3",
3
+ "version": "0.16.4",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "loop-agent": "bin/loop-agent.js",