loopforge 1.8.0 → 1.15.1

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 (88) hide show
  1. package/dist/backends/fs.d.ts.map +1 -1
  2. package/dist/backends/fs.js +13 -10
  3. package/dist/backends/fs.js.map +1 -1
  4. package/dist/backends/interface.d.ts +2 -0
  5. package/dist/backends/interface.d.ts.map +1 -1
  6. package/dist/builder.d.ts +13 -10
  7. package/dist/builder.d.ts.map +1 -1
  8. package/dist/builder.js +117 -96
  9. package/dist/builder.js.map +1 -1
  10. package/dist/enforcement-gate.d.ts +44 -0
  11. package/dist/enforcement-gate.d.ts.map +1 -0
  12. package/dist/enforcement-gate.js +253 -0
  13. package/dist/enforcement-gate.js.map +1 -0
  14. package/dist/engine.d.ts +13 -6
  15. package/dist/engine.d.ts.map +1 -1
  16. package/dist/engine.js +127 -171
  17. package/dist/engine.js.map +1 -1
  18. package/dist/index.d.ts +5 -5
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +4 -4
  21. package/dist/index.js.map +1 -1
  22. package/dist/loop-compiler.d.ts +10 -2
  23. package/dist/loop-compiler.d.ts.map +1 -1
  24. package/dist/loop-compiler.js +882 -583
  25. package/dist/loop-compiler.js.map +1 -1
  26. package/dist/mcp/session.d.ts +12 -2
  27. package/dist/mcp/session.d.ts.map +1 -1
  28. package/dist/mcp/session.js +127 -64
  29. package/dist/mcp/session.js.map +1 -1
  30. package/dist/mcp/tools.js +4 -4
  31. package/dist/memory-bridge.js +1 -1
  32. package/dist/memory-bridge.js.map +1 -1
  33. package/dist/observability.d.ts +1 -1
  34. package/dist/observability.js +1 -1
  35. package/dist/policy.d.ts +80 -10
  36. package/dist/policy.d.ts.map +1 -1
  37. package/dist/policy.js +101 -30
  38. package/dist/policy.js.map +1 -1
  39. package/dist/protocol.d.ts +70 -16
  40. package/dist/protocol.d.ts.map +1 -1
  41. package/dist/protocol.js +40 -8
  42. package/dist/protocol.js.map +1 -1
  43. package/dist/replay.js +7 -7
  44. package/dist/replay.js.map +1 -1
  45. package/dist/runtime.d.ts +11 -7
  46. package/dist/runtime.d.ts.map +1 -1
  47. package/dist/runtime.js +125 -144
  48. package/dist/runtime.js.map +1 -1
  49. package/dist/tests/builder.test.js +42 -28
  50. package/dist/tests/builder.test.js.map +1 -1
  51. package/dist/tests/enforcement-gate.test.d.ts +2 -0
  52. package/dist/tests/enforcement-gate.test.d.ts.map +1 -0
  53. package/dist/tests/enforcement-gate.test.js +328 -0
  54. package/dist/tests/enforcement-gate.test.js.map +1 -0
  55. package/dist/tests/engine.test.js +22 -22
  56. package/dist/tests/engine.test.js.map +1 -1
  57. package/dist/tests/generate-schema.test.js +10 -7
  58. package/dist/tests/generate-schema.test.js.map +1 -1
  59. package/dist/tests/loop-compiler.test.js +273 -47
  60. package/dist/tests/loop-compiler.test.js.map +1 -1
  61. package/dist/tests/mcp.test.js +31 -11
  62. package/dist/tests/mcp.test.js.map +1 -1
  63. package/dist/tests/memory-bridge.test.js +0 -1
  64. package/dist/tests/memory-bridge.test.js.map +1 -1
  65. package/dist/tests/policy.test.js +6 -16
  66. package/dist/tests/policy.test.js.map +1 -1
  67. package/dist/tests/protocol.test.js +3 -2
  68. package/dist/tests/protocol.test.js.map +1 -1
  69. package/dist/tests/replay.test.js +9 -9
  70. package/dist/tests/replay.test.js.map +1 -1
  71. package/dist/tests/runtime.test.js +27 -13
  72. package/dist/tests/runtime.test.js.map +1 -1
  73. package/dist/tests/verification-gate.test.js +1 -1
  74. package/dist/tests/verification-gate.test.js.map +1 -1
  75. package/dist/verification-gate.d.ts +8 -2
  76. package/dist/verification-gate.d.ts.map +1 -1
  77. package/dist/verification-gate.js +5 -4
  78. package/dist/verification-gate.js.map +1 -1
  79. package/loop_policy.json +13 -26
  80. package/package.json +1 -1
  81. package/skills/perception/SKILL.md +42 -23
  82. package/skills/prompt-techniques/SKILL.md +52 -52
  83. package/skills/prompt-techniques/references/chain-of-thought.md +207 -207
  84. package/skills/prompt-techniques/references/few-shot.md +174 -174
  85. package/skills/prompt-techniques/references/least-to-most.md +182 -182
  86. package/skills/prompt-techniques/references/step-back.md +160 -160
  87. package/skills/prompt-techniques/references/tree-of-thought.md +191 -191
  88. package/skills/prompt-techniques/references/zero-shot.md +97 -97
@@ -1,7 +1,7 @@
1
1
  /** Tests for technique routing and quality scoring. */
2
2
  import { describe, it, beforeEach } from "node:test";
3
3
  import assert from "node:assert/strict";
4
- import { routeTechnique, routeTechniqueAdaptive, scoreQuality, } from "../builder.js";
4
+ import { routeTechnique, routeTechniqueAdaptive, } from "../builder.js";
5
5
  import { resetPolicy } from "../policy.js";
6
6
  describe("Builder — Route Technique", () => {
7
7
  beforeEach(() => resetPolicy());
@@ -44,49 +44,28 @@ describe("Builder — Route Technique", () => {
44
44
  assert.equal(analysis.technique, "zero-shot");
45
45
  });
46
46
  });
47
- describe("Builder — Score Quality", () => {
48
- it("returns 5 for success with no violations or fixes", () => {
49
- assert.equal(scoreQuality({ success: true, constraint_violations: [], manual_fixes_needed: "" }), 5);
50
- });
51
- it("returns 4 for success with manual fixes needed but no violations", () => {
52
- assert.equal(scoreQuality({ success: true, constraint_violations: [], manual_fixes_needed: "fix formatting" }), 4);
53
- });
54
- it("returns 3 for success with constraint violations", () => {
55
- assert.equal(scoreQuality({ success: true, constraint_violations: ["missing check"] }), 3);
56
- });
57
- it("returns 2 for failure with constraint violations", () => {
58
- assert.equal(scoreQuality({ success: false, constraint_violations: ["XSS vulnerability"] }), 2);
59
- });
60
- it("returns 1 for failure with no constraint violations", () => {
61
- assert.equal(scoreQuality({ success: false, constraint_violations: [] }), 1);
62
- });
63
- it("returns 0 for null feedback", () => {
64
- assert.equal(scoreQuality(null), 0);
65
- });
66
- });
67
- describe("Builder — Adaptive routing", () => {
68
- it("falls back to keyword heuristic when no vault context", () => {
69
- // "Audit" + "fix" → continuous + high → few-shot-cot
47
+ describe("Builder — Tier-gated routing", () => {
48
+ it("uses keyword heuristic when no vault context (Tier 1 default)", () => {
70
49
  const analysis = routeTechniqueAdaptive("Fix the encryption protocol security audit", null, "");
71
50
  assert.equal(analysis.technique, "few-shot-cot");
72
51
  assert.equal(analysis.was_rotated, false);
73
52
  });
74
- it("falls back to keyword heuristic when no loop_id", () => {
53
+ it("uses keyword heuristic when no loop_id (Tier 1 default)", () => {
75
54
  const analysis = routeTechniqueAdaptive("Fix the encryption protocol security audit", { results: [] }, "");
76
55
  assert.equal(analysis.technique, "few-shot-cot");
77
56
  assert.equal(analysis.was_rotated, false);
78
57
  });
79
- it("does not rotate when quality scores are high", () => {
58
+ it("stays in Tier 1 by default", () => {
80
59
  const vaultContext = {
81
60
  results: [
82
61
  {
83
62
  loop_lineage: {
84
63
  loop_id: "test-loop",
85
64
  round: 1,
86
- quality_score: 5,
65
+ success: true,
87
66
  },
88
67
  technique_used: "few-shot-cot",
89
- quality_score: 5,
68
+ success: true,
90
69
  },
91
70
  ],
92
71
  };
@@ -94,5 +73,40 @@ describe("Builder — Adaptive routing", () => {
94
73
  assert.equal(analysis.technique, "few-shot-cot");
95
74
  assert.equal(analysis.was_rotated, false);
96
75
  });
76
+ it("allows Tier 2 on checkpoint boundary", () => {
77
+ // Task triggers step-back keyword → Tier 2, normally downgraded
78
+ // But with isCheckpoint=true, should be allowed
79
+ const analysis = routeTechniqueAdaptive("重构 legacy 系统", null, "", true);
80
+ assert.equal(analysis.technique, "step-back");
81
+ });
82
+ it("downgrades Tier 2 to Tier 1 in normal round", () => {
83
+ // "重构 legacy 系统" triggers step-back (Tier 2), but without checkpoint it downgrades
84
+ const analysis = routeTechniqueAdaptive("重构 legacy 系统");
85
+ // step-back downgrades to few-shot-cot
86
+ assert.ok(["zero-shot", "few-shot", "zero-shot-cot", "few-shot-cot"].includes(analysis.technique));
87
+ });
88
+ // v1.15: Tier escalation removed — Agent freely chooses at L2.
89
+ // Consecutive failures no longer force Tier 2 techniques.
90
+ it("stays in Tier 1 after consecutive failures (v1.15 — escalation removed)", () => {
91
+ const vaultContext = {
92
+ results: [
93
+ {
94
+ loop_lineage: { loop_id: "test-loop", round: 1 },
95
+ success: false,
96
+ },
97
+ {
98
+ loop_lineage: { loop_id: "test-loop", round: 2 },
99
+ success: false,
100
+ },
101
+ {
102
+ loop_lineage: { loop_id: "test-loop", round: 3 },
103
+ success: false,
104
+ },
105
+ ],
106
+ };
107
+ const analysis = routeTechniqueAdaptive("Fix the encryption protocol security audit", vaultContext, "test-loop");
108
+ // Tier 1 only in normal round (no escalation)
109
+ assert.ok(["zero-shot", "few-shot", "zero-shot-cot", "few-shot-cot"].includes(analysis.technique));
110
+ });
97
111
  });
98
112
  //# sourceMappingURL=builder.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"builder.test.js","sourceRoot":"","sources":["../../src/tests/builder.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"builder.test.js","sourceRoot":"","sources":["../../src/tests/builder.test.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EACL,cAAc,EACd,sBAAsB,GAEvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,UAAU,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IAEhC,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,iFAAiF;QACjF,MAAM,QAAQ,GAAG,cAAc,CAAC,oDAAoD,CAAC,CAAC;QACtF,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;QACpD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,QAAQ,GAAG,cAAc,CAAC,6CAA6C,CAAC,CAAC;QAC/E,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,QAAQ,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC,CAAE,0BAA0B;QAC3E,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,QAAQ,GAAG,cAAc,CAAC,mEAAmE,CAAC,CAAC;QACrG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,QAAQ,GAAG,cAAc,CAAC,8DAA8D,CAAC,CAAC;QAChG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,QAAQ,GAAG,cAAc,CAAC,6BAA6B,CAAC,CAAC;QAC/D,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,QAAQ,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC,CAAE,aAAa;QACnD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC5C,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,QAAQ,GAAG,sBAAsB,CAAC,4CAA4C,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QAChG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,QAAQ,GAAG,sBAAsB,CAAC,4CAA4C,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3G,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,YAAY,GAAG;YACnB,OAAO,EAAE;gBACP;oBACE,YAAY,EAAE;wBACZ,OAAO,EAAE,WAAW;wBACpB,KAAK,EAAE,CAAC;wBACR,OAAO,EAAE,IAAI;qBACd;oBACD,cAAc,EAAE,cAAc;oBAC9B,OAAO,EAAE,IAAI;iBACd;aACF;SACF,CAAC;QACF,MAAM,QAAQ,GAAG,sBAAsB,CAAC,4CAA4C,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;QACjH,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,gEAAgE;QAChE,gDAAgD;QAChD,MAAM,QAAQ,GAAG,sBAAsB,CAAC,cAAc,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QACxE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,mFAAmF;QACnF,MAAM,QAAQ,GAAG,sBAAsB,CAAC,cAAc,CAAC,CAAC;QACxD,uCAAuC;QACvC,MAAM,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,cAAc,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IACrG,CAAC,CAAC,CAAC;IAEH,+DAA+D;IAC/D,0DAA0D;IAC1D,EAAE,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACjF,MAAM,YAAY,GAAG;YACnB,OAAO,EAAE;gBACP;oBACE,YAAY,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE;oBAChD,OAAO,EAAE,KAAK;iBACf;gBACD;oBACE,YAAY,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE;oBAChD,OAAO,EAAE,KAAK;iBACf;gBACD;oBACE,YAAY,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE;oBAChD,OAAO,EAAE,KAAK;iBACf;aACF;SACF,CAAC;QACF,MAAM,QAAQ,GAAG,sBAAsB,CAAC,4CAA4C,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;QACjH,8CAA8C;QAC9C,MAAM,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,cAAc,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;IACrG,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=enforcement-gate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enforcement-gate.test.d.ts","sourceRoot":"","sources":["../../src/tests/enforcement-gate.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,328 @@
1
+ /** Tests for enforcement-gate — Layer 2 round-boundary runtime enforcement. */
2
+ import { describe, it } from "node:test";
3
+ import assert from "node:assert/strict";
4
+ import { makeEnforcementResult, makeExecutionEvidence, makeSelfEvaluation, makeVerificationFlag, makeVerificationResult, } from "../protocol.js";
5
+ import { enforceRound, buildRejectionPrompt } from "../enforcement-gate.js";
6
+ // ═══════════════════════════════════════════════════════════════════════════
7
+ // Helpers
8
+ // ═══════════════════════════════════════════════════════════════════════════
9
+ /** Build a minimal SelfEvaluation for testing. */
10
+ function se(overrides = {}) {
11
+ return makeSelfEvaluation({
12
+ success: true,
13
+ output_summary: "Task completed.",
14
+ constraint_violations: [],
15
+ should_continue: true,
16
+ ...overrides,
17
+ });
18
+ }
19
+ /** Build a trusted VerificationResult with no flags. */
20
+ function trusted() {
21
+ return makeVerificationResult({ verdict: "trusted", flags: [] });
22
+ }
23
+ /** Build a VerificationResult with a "success_with_remaining_criteria" error flag. */
24
+ function contradictedSuccessWithRemaining(criteria) {
25
+ return makeVerificationResult({
26
+ verdict: "contradicted",
27
+ flags: [
28
+ makeVerificationFlag({
29
+ severity: "error",
30
+ field: "success",
31
+ check: "success_with_remaining_criteria",
32
+ detail: `Agent claims success but ${criteria.length} criteria remain unmet: ${criteria.join("; ")}`,
33
+ }),
34
+ ],
35
+ });
36
+ }
37
+ /** Build a VerificationResult with a "recurring_violation" error flag. */
38
+ function contradictedRecurringViolation(violation) {
39
+ return makeVerificationResult({
40
+ verdict: "contradicted",
41
+ flags: [
42
+ makeVerificationFlag({
43
+ severity: "error",
44
+ field: "constraint_violations",
45
+ check: "recurring_violation",
46
+ detail: `Constraint violation "${violation}" has appeared in 3 consecutive rounds without resolution`,
47
+ }),
48
+ ],
49
+ });
50
+ }
51
+ /** Build a vault entry with round and optional progress data. */
52
+ function vaultRound(round, progressEstimate) {
53
+ const entry = {
54
+ task_id: `loop:test-loop:r${round}`,
55
+ loop_id: "test-loop",
56
+ loop_lineage: { round, success: true, task: "test task" },
57
+ };
58
+ if (typeof progressEstimate === "number") {
59
+ entry.execution_evidence = {
60
+ files_changed: ["src/foo.ts"],
61
+ test_results: { passed: 1, failed: 0, skipped: 0 },
62
+ success_criteria_met: [],
63
+ success_criteria_remaining: [],
64
+ progress_estimate: progressEstimate,
65
+ };
66
+ }
67
+ return entry;
68
+ }
69
+ // ═══════════════════════════════════════════════════════════════════════════
70
+ // Happy path — trusted verdict, no issues
71
+ // ═══════════════════════════════════════════════════════════════════════════
72
+ describe("enforcement-gate — happy path", () => {
73
+ it("accepts a round with trusted verdict and clean self-eval", () => {
74
+ const curr = se({
75
+ success: false,
76
+ execution_evidence: makeExecutionEvidence({
77
+ files_changed: ["src/foo.ts"],
78
+ test_results: { passed: 3, failed: 1, skipped: 0 },
79
+ progress_estimate: 0.5,
80
+ }),
81
+ });
82
+ const result = enforceRound(curr, trusted(), 2, [], 0);
83
+ assert.equal(result.action, "accept");
84
+ assert.equal(result.reason, "");
85
+ });
86
+ it("accepts a round with suspect verdict (warn only, not error)", () => {
87
+ const curr = se({
88
+ success: false,
89
+ execution_evidence: makeExecutionEvidence({
90
+ files_changed: ["src/bar.ts"],
91
+ test_results: { passed: 5, failed: 0, skipped: 0 },
92
+ progress_estimate: 0.3,
93
+ }),
94
+ });
95
+ const suspect = makeVerificationResult({
96
+ verdict: "suspect",
97
+ flags: [
98
+ makeVerificationFlag({
99
+ severity: "warn",
100
+ field: "progress_estimate",
101
+ check: "progress_regression",
102
+ detail: "Progress dropped from 0.5 to 0.3",
103
+ }),
104
+ ],
105
+ });
106
+ const result = enforceRound(curr, suspect, 2, [], 0);
107
+ assert.equal(result.action, "accept");
108
+ });
109
+ it("accepts round 1 with no prior vault data", () => {
110
+ const curr = se({ success: false });
111
+ const result = enforceRound(curr, trusted(), 1, [], 0);
112
+ assert.equal(result.action, "accept");
113
+ });
114
+ });
115
+ // ═══════════════════════════════════════════════════════════════════════════
116
+ // R1: success=true with remaining criteria
117
+ // ═══════════════════════════════════════════════════════════════════════════
118
+ describe("enforcement-gate — R1: fake success", () => {
119
+ it("rejects when agent claims success but criteria remain unmet", () => {
120
+ const curr = se({
121
+ success: true,
122
+ execution_evidence: makeExecutionEvidence({
123
+ files_changed: ["src/foo.ts"],
124
+ success_criteria_met: ["criteria-1"],
125
+ success_criteria_remaining: ["criteria-2", "criteria-3"],
126
+ progress_estimate: 0.5,
127
+ }),
128
+ });
129
+ const result = enforceRound(curr, contradictedSuccessWithRemaining(["criteria-2", "criteria-3"]), 3, [], 0);
130
+ assert.equal(result.action, "reject");
131
+ assert.ok(result.reason.includes("criteria remain unmet"));
132
+ assert.ok(result.fix_instructions.length > 0);
133
+ });
134
+ });
135
+ // ═══════════════════════════════════════════════════════════════════════════
136
+ // R2: recurring violation
137
+ // ═══════════════════════════════════════════════════════════════════════════
138
+ describe("enforcement-gate — R2: recurring violation", () => {
139
+ it("rejects when same violation appears in 3 consecutive rounds", () => {
140
+ const curr = se({
141
+ success: false,
142
+ constraint_violations: ["missing docs"],
143
+ });
144
+ const result = enforceRound(curr, contradictedRecurringViolation("missing docs"), 4, [], 0);
145
+ assert.equal(result.action, "reject");
146
+ assert.ok(result.reason.includes("3 consecutive rounds"));
147
+ assert.ok(result.fix_instructions.includes("DIFFERENT approach"));
148
+ });
149
+ });
150
+ // ═══════════════════════════════════════════════════════════════════════════
151
+ // R3: empty success — no files changed, no tests, claims success
152
+ // ═══════════════════════════════════════════════════════════════════════════
153
+ describe("enforcement-gate — R3: empty success", () => {
154
+ it("rejects when agent claims success with no files and no tests", () => {
155
+ const curr = se({
156
+ success: true,
157
+ execution_evidence: makeExecutionEvidence({
158
+ files_changed: [],
159
+ test_results: null,
160
+ progress_estimate: 1.0,
161
+ }),
162
+ });
163
+ const result = enforceRound(curr, trusted(), 2, [], 0);
164
+ assert.equal(result.action, "reject");
165
+ assert.ok(result.reason.includes("no verifiable evidence"));
166
+ });
167
+ it("accepts when success=true with files_changed (not empty)", () => {
168
+ const curr = se({
169
+ success: true,
170
+ execution_evidence: makeExecutionEvidence({
171
+ files_changed: ["src/fixed.ts"],
172
+ test_results: { passed: 10, failed: 0, skipped: 0 },
173
+ progress_estimate: 1.0,
174
+ }),
175
+ });
176
+ const result = enforceRound(curr, trusted(), 2, [], 0);
177
+ assert.equal(result.action, "accept");
178
+ });
179
+ it("skips when execution_evidence is undefined (heuristic fallback)", () => {
180
+ // Heuristic self-evaluations have no execution_evidence.
181
+ // R3 should not fire in this case — it only fires when
182
+ // execution_evidence IS provided but shows empty work.
183
+ const curr = makeSelfEvaluation({
184
+ success: true,
185
+ output_summary: "Done.",
186
+ constraint_violations: [],
187
+ should_continue: true,
188
+ });
189
+ // Explicitly remove execution_evidence (default factory sets it)
190
+ curr.execution_evidence = undefined;
191
+ const result = enforceRound(curr, trusted(), 2, [], 0);
192
+ assert.equal(result.action, "accept");
193
+ });
194
+ });
195
+ // ═══════════════════════════════════════════════════════════════════════════
196
+ // R4: progress stall
197
+ // ═══════════════════════════════════════════════════════════════════════════
198
+ describe("enforcement-gate — R4: progress stall", () => {
199
+ it("rejects when progress is flat for 3 rounds", () => {
200
+ const curr = se({
201
+ success: false,
202
+ execution_evidence: makeExecutionEvidence({
203
+ files_changed: ["src/foo.ts"],
204
+ progress_estimate: 0.33,
205
+ }),
206
+ });
207
+ const vault = [
208
+ vaultRound(1, 0.30),
209
+ vaultRound(2, 0.31),
210
+ vaultRound(3, 0.32),
211
+ ];
212
+ const result = enforceRound(curr, trusted(), 4, vault, 0);
213
+ assert.equal(result.action, "reject");
214
+ assert.ok(result.reason.includes("stalled"));
215
+ });
216
+ it("accepts when progress is increasing", () => {
217
+ const curr = se({
218
+ success: false,
219
+ execution_evidence: makeExecutionEvidence({
220
+ files_changed: ["src/foo.ts"],
221
+ progress_estimate: 0.80,
222
+ }),
223
+ });
224
+ const vault = [
225
+ vaultRound(1, 0.30),
226
+ vaultRound(2, 0.50),
227
+ vaultRound(3, 0.70),
228
+ ];
229
+ const result = enforceRound(curr, trusted(), 4, vault, 0);
230
+ assert.equal(result.action, "accept");
231
+ });
232
+ it("terminates on second consecutive stall rejection", () => {
233
+ const curr = se({
234
+ success: false,
235
+ execution_evidence: makeExecutionEvidence({
236
+ files_changed: ["src/foo.ts"],
237
+ progress_estimate: 0.33,
238
+ }),
239
+ });
240
+ const vault = [
241
+ vaultRound(1, 0.30),
242
+ vaultRound(2, 0.31),
243
+ vaultRound(3, 0.32),
244
+ ];
245
+ // consecutiveRejections=1 (was already rejected once before)
246
+ const result = enforceRound(curr, trusted(), 4, vault, 1);
247
+ assert.equal(result.action, "terminate");
248
+ assert.ok(result.reason.includes("previous rejection"));
249
+ });
250
+ it("does not fire with less than 3 rounds of vault data", () => {
251
+ const curr = se({
252
+ success: false,
253
+ execution_evidence: makeExecutionEvidence({
254
+ progress_estimate: 0.32,
255
+ }),
256
+ });
257
+ const vault = [vaultRound(1, 0.30)];
258
+ const result = enforceRound(curr, trusted(), 2, vault, 0);
259
+ assert.equal(result.action, "accept");
260
+ });
261
+ });
262
+ // ═══════════════════════════════════════════════════════════════════════════
263
+ // R5: max rejections
264
+ // ═══════════════════════════════════════════════════════════════════════════
265
+ describe("enforcement-gate — R5: max rejections", () => {
266
+ it("terminates after 2 consecutive rejections", () => {
267
+ const curr = se({ success: false });
268
+ const result = enforceRound(curr, trusted(), 3, [], 2);
269
+ assert.equal(result.action, "terminate");
270
+ assert.ok(result.reason.includes("consecutive enforcement rejections"));
271
+ });
272
+ it("does not terminate with only 1 rejection", () => {
273
+ const curr = se({ success: false });
274
+ const result = enforceRound(curr, trusted(), 3, [], 1);
275
+ assert.equal(result.action, "accept");
276
+ });
277
+ });
278
+ // ═══════════════════════════════════════════════════════════════════════════
279
+ // Priority — R1 takes precedence over R3 when both conditions exist
280
+ // ═══════════════════════════════════════════════════════════════════════════
281
+ describe("enforcement-gate — rule priority", () => {
282
+ it("R1 (fake success) fires before R3 (empty success)", () => {
283
+ const curr = se({
284
+ success: true,
285
+ execution_evidence: makeExecutionEvidence({
286
+ files_changed: [], // triggers R3
287
+ test_results: null, // triggers R3
288
+ success_criteria_met: ["x"],
289
+ success_criteria_remaining: ["y", "z"], // triggers R1
290
+ progress_estimate: 1.0,
291
+ }),
292
+ });
293
+ const result = enforceRound(curr, contradictedSuccessWithRemaining(["y", "z"]), 2, [], 0);
294
+ // R1 should fire (criteria remaining), not R3 (empty success)
295
+ assert.equal(result.action, "reject");
296
+ assert.ok(result.reason.includes("criteria remain unmet"));
297
+ });
298
+ });
299
+ // ═══════════════════════════════════════════════════════════════════════════
300
+ // buildRejectionPrompt
301
+ // ═══════════════════════════════════════════════════════════════════════════
302
+ describe("buildRejectionPrompt", () => {
303
+ it("produces a prompt containing REJECTED, reason, and retry instructions", () => {
304
+ const enforceResult = makeEnforcementResult({
305
+ action: "reject",
306
+ reason: "Agent claims success but 3 criteria remain unmet.",
307
+ fix_instructions: "Complete all criteria or set success=false.",
308
+ });
309
+ const prompt = buildRejectionPrompt(5, "Audit the ERC20 token", enforceResult);
310
+ assert.ok(prompt.includes("REJECTED"));
311
+ assert.ok(prompt.includes("Round 5"));
312
+ assert.ok(prompt.includes("criteria remain unmet"));
313
+ assert.ok(prompt.includes("Complete all criteria"));
314
+ assert.ok(prompt.includes("Audit the ERC20 token"));
315
+ assert.ok(prompt.includes("Retry"));
316
+ assert.ok(prompt.includes("do NOT advance"));
317
+ });
318
+ it("includes the task in the retry section", () => {
319
+ const enforceResult = makeEnforcementResult({
320
+ action: "reject",
321
+ reason: "Test reason.",
322
+ fix_instructions: "Test fix.",
323
+ });
324
+ const prompt = buildRejectionPrompt(2, "Fix bugs in auth module", enforceResult);
325
+ assert.ok(prompt.includes("Fix bugs in auth module"));
326
+ });
327
+ });
328
+ //# sourceMappingURL=enforcement-gate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enforcement-gate.test.js","sourceRoot":"","sources":["../../src/tests/enforcement-gate.test.ts"],"names":[],"mappings":"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"}
@@ -25,8 +25,8 @@ describe("Engine — Initialisation", () => {
25
25
  it("createEngine returns LoopForgeEngine instance", () => {
26
26
  const engine = createEngine("skills");
27
27
  assert.ok(engine instanceof LoopForgeEngine);
28
- assert.equal(engine.skillsDir, "skills");
29
28
  assert.equal(engine.state, null);
29
+ assert.equal(engine.lastTask, null);
30
30
  });
31
31
  it("engine lazy-inits state on first invocation", () => {
32
32
  const engine = createEngine();
@@ -47,7 +47,7 @@ describe("Engine — Feedback mode", () => {
47
47
  assert.equal(result.status, AgentStatus.ERROR);
48
48
  assert.ok(result.response.error.includes("feedback payload"));
49
49
  });
50
- it("returns OK with quality score when feedback provided", () => {
50
+ it("returns OK with success flag when feedback provided", () => {
51
51
  const engine = createEngine();
52
52
  const req = makeRequest({
53
53
  mode: Mode.FEEDBACK,
@@ -60,31 +60,31 @@ describe("Engine — Feedback mode", () => {
60
60
  });
61
61
  const result = engine.invokeFeedback(req);
62
62
  assert.equal(result.status, AgentStatus.OK);
63
- assert.ok(result.response.prompt.includes("Quality Score: 5/5"));
63
+ assert.ok(result.response.prompt.includes("Success: true"));
64
64
  });
65
- it("scores quality=4 for success with fixes but no violations", () => {
65
+ it("returns OK with success=false for failures", () => {
66
66
  const engine = createEngine();
67
67
  const req = makeRequest({
68
68
  mode: Mode.FEEDBACK,
69
69
  feedback: makeExecutionFeedback({
70
- success: true,
70
+ success: false,
71
71
  constraint_violations: [],
72
72
  manual_fixes_needed: "formatting",
73
73
  output: "Works with manual tweaks",
74
74
  }),
75
75
  });
76
76
  const result = engine.invokeFeedback(req);
77
- assert.ok(result.response.prompt.includes("Quality Score: 4/5"));
77
+ assert.ok(result.response.prompt.includes("Success: false"));
78
78
  });
79
- it("updates quality trend in state", () => {
79
+ it("updates success trend in state", () => {
80
80
  const engine = createEngine();
81
81
  const req = makeRequest({
82
82
  mode: Mode.FEEDBACK,
83
83
  feedback: makeExecutionFeedback({ success: true, output: "ok" }),
84
84
  });
85
85
  engine.invokeFeedback(req);
86
- assert.equal(engine.state.quality_trend.length, 1);
87
- assert.equal(engine.state.quality_trend[0], 5);
86
+ assert.equal(engine.state.success_trend.length, 1);
87
+ assert.equal(engine.state.success_trend[0], true);
88
88
  });
89
89
  });
90
90
  describe("Engine — Circuit breaker", () => {
@@ -99,25 +99,25 @@ describe("Engine — Circuit breaker", () => {
99
99
  mode: Mode.FEEDBACK,
100
100
  feedback: makeExecutionFeedback({ success: true, output: "ok" }),
101
101
  })); // init state
102
- engine.state.quality_trend = [5, 4];
102
+ engine.state.success_trend = [true, true];
103
103
  assert.equal(engine.shouldBreak(), false);
104
104
  });
105
- it("returns true when quality is non-increasing for 3 rounds", () => {
105
+ it("returns true when 3 consecutive failures", () => {
106
106
  const engine = createEngine();
107
107
  engine.invokeFeedback(makeRequest({
108
108
  mode: Mode.FEEDBACK,
109
109
  feedback: makeExecutionFeedback({ success: true, output: "ok" }),
110
110
  }));
111
- engine.state.quality_trend = [3, 3, 3];
111
+ engine.state.success_trend = [false, false, false];
112
112
  assert.equal(engine.shouldBreak(), true);
113
113
  });
114
- it("returns false when quality is improving", () => {
114
+ it("returns false when all successes (no longer trips on flat success)", () => {
115
115
  const engine = createEngine();
116
116
  engine.invokeFeedback(makeRequest({
117
117
  mode: Mode.FEEDBACK,
118
118
  feedback: makeExecutionFeedback({ success: true, output: "ok" }),
119
119
  }));
120
- engine.state.quality_trend = [3, 4, 5];
120
+ engine.state.success_trend = [true, true, true];
121
121
  assert.equal(engine.shouldBreak(), false);
122
122
  });
123
123
  });
@@ -197,7 +197,6 @@ describe("Engine — P0-P5 Cognitive Evolution (v1.7 E2E)", () => {
197
197
  output_summary: "Found 2 reentrancy bugs",
198
198
  constraint_violations: [],
199
199
  manual_fixes_needed: "",
200
- quality_score: 5,
201
200
  discovered_constraints: ["Use SafeERC20 for all external calls"],
202
201
  objective_refinement: "Scope includes upgradeable proxy patterns",
203
202
  emerged_subtasks: ["Audit proxy init", "Verify timelock"],
@@ -250,7 +249,6 @@ describe("Engine — P0-P5 Cognitive Evolution (v1.7 E2E)", () => {
250
249
  output_summary: "Fixed reentrancy in withdraw()",
251
250
  constraint_violations: [],
252
251
  manual_fixes_needed: "",
253
- quality_score: 5,
254
252
  execution_evidence: {
255
253
  files_changed: ["contracts/Token.sol", "test/Token.test.ts"],
256
254
  test_results: { passed: 24, failed: 0, skipped: 0 },
@@ -261,11 +259,15 @@ describe("Engine — P0-P5 Cognitive Evolution (v1.7 E2E)", () => {
261
259
  },
262
260
  });
263
261
  assert.equal(r2.status, AgentStatus.OK);
262
+ // v1.14 Thin Prompt: progress dashboard lives in state file, not in prompt
263
+ const stateFile = r2.response.state_file_content;
264
+ assert.ok(stateFile, "P4: state_file_content should be set for L2 compile");
265
+ assert.ok(stateFile.includes("Progress Dashboard"), "P4: progress dashboard in state file");
266
+ assert.ok(stateFile.includes("1/3"), "P4: criteria count in state file");
267
+ assert.ok(stateFile.includes("Token.sol"), "P4: files_changed in state file");
268
+ // Thin prompt: progress dashboard should NOT be in the prompt text
264
269
  const prompt = r2.response.prompt;
265
- // P4: Progress dashboard should appear (L2 recompile)
266
- assert.ok(prompt.includes("Progress Dashboard"), "P4: progress dashboard missing");
267
- assert.ok(prompt.includes("1/3"), "P4: criteria count missing");
268
- assert.ok(prompt.includes("Token.sol"), "P4: files_changed missing");
270
+ assert.ok(!prompt.includes("Progress Dashboard"), "P4: thin prompt — dashboard in state file only");
269
271
  });
270
272
  it("P5: wrong_assumptions are forwarded to compiler as key lessons", () => {
271
273
  const engine = createEngine();
@@ -290,7 +292,6 @@ describe("Engine — P0-P5 Cognitive Evolution (v1.7 E2E)", () => {
290
292
  output_summary: "Found missing access control",
291
293
  constraint_violations: [],
292
294
  manual_fixes_needed: "",
293
- quality_score: 2,
294
295
  wrong_assumptions: ["Assumed OZ v4.0 has no known issues"],
295
296
  retracted_constraints: [],
296
297
  revised_success_criteria: [],
@@ -325,7 +326,6 @@ describe("Engine — P0-P5 Cognitive Evolution (v1.7 E2E)", () => {
325
326
  output_summary: "Audited contracts",
326
327
  constraint_violations: [],
327
328
  manual_fixes_needed: "",
328
- quality_score: 5,
329
329
  discovered_constraints: ["No external deps"],
330
330
  retracted_constraints: ["No external deps"],
331
331
  wrong_assumptions: [],