@cleocode/playbooks 2026.5.60 → 2026.5.62

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cleocode/playbooks",
3
- "version": "2026.5.60",
3
+ "version": "2026.5.62",
4
4
  "description": "Playbook DSL + runtime for CLEO — T889 Orchestration Coherence v3",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -19,8 +19,8 @@
19
19
  "dependencies": {
20
20
  "drizzle-orm": "1.0.0-beta.22-ec7b61d",
21
21
  "js-yaml": "^4.1.0",
22
- "@cleocode/contracts": "2026.5.60",
23
- "@cleocode/core": "2026.5.60"
22
+ "@cleocode/contracts": "2026.5.62",
23
+ "@cleocode/core": "2026.5.62"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/js-yaml": "^4.0.9",
@@ -132,6 +132,10 @@ function alwaysSucceed(input: AgentDispatchInput): AgentDispatchResult {
132
132
  case 'validate':
133
133
  extraFields.passed = true;
134
134
  break;
135
+ case 'audit': // T9216: auditor node
136
+ extraFields.passed = true;
137
+ extraFields.auditPassed = true;
138
+ break;
135
139
  case 'research':
136
140
  extraFields.summary = 'research summary';
137
141
  extraFields.risks = [];
@@ -157,6 +161,12 @@ function alwaysSucceed(input: AgentDispatchInput): AgentDispatchResult {
157
161
  case 'publish':
158
162
  extraFields.published = true;
159
163
  break;
164
+ case 'test': // ensure testsPassed for ivtr test→released edge (T9216)
165
+ extraFields.testsPassed = true;
166
+ break;
167
+ case 'released': // T9216: final node
168
+ extraFields.released = true;
169
+ break;
160
170
  default:
161
171
  break;
162
172
  }
@@ -274,27 +284,35 @@ describe('T934: starter playbooks — E2E against stubbed dispatcher', () => {
274
284
  // ivtr — implement → validate → test, with inject_into wiring for retries.
275
285
  // -------------------------------------------------------------------------
276
286
  describe('ivtr.cantbook', () => {
277
- it('parses cleanly and declares implement/validate/test with iteration caps', () => {
287
+ it('parses cleanly and declares implement/validate/audit/test/released with iteration caps (T9216)', () => {
278
288
  const { definition } = loadStarter('ivtr');
279
289
  expect(definition.name).toBe('ivtr');
280
- expect(definition.nodes).toHaveLength(3);
281
- expect(definition.nodes.map((n) => n.id)).toEqual(['implement', 'validate', 'test']);
290
+ // T9216: audit and released nodes added
291
+ expect(definition.nodes.length).toBeGreaterThanOrEqual(4);
292
+ const nodeIds = definition.nodes.map((n) => n.id);
293
+ expect(nodeIds).toContain('implement');
294
+ expect(nodeIds).toContain('validate');
295
+ expect(nodeIds).toContain('audit'); // T9216
296
+ expect(nodeIds).toContain('test');
282
297
 
283
298
  const implementNode = definition.nodes.find((n) => n.id === 'implement');
284
299
  const validateNode = definition.nodes.find((n) => n.id === 'validate');
300
+ const auditNode = definition.nodes.find((n) => n.id === 'audit'); // T9216
285
301
  const testNode = definition.nodes.find((n) => n.id === 'test');
286
302
 
287
303
  // Iteration caps are populated (runtime needs them for loop bounds).
288
304
  expect(implementNode?.on_failure?.max_iterations).toBe(3);
289
305
  expect(validateNode?.on_failure?.max_iterations).toBe(2);
306
+ expect(auditNode?.on_failure?.max_iterations).toBe(2); // T9216
290
307
  expect(testNode?.on_failure?.max_iterations).toBe(2);
291
308
 
292
- // validate + test both bounce back to implement on sustained failure.
309
+ // validate, audit, test all bounce back to implement on sustained failure.
293
310
  expect(validateNode?.on_failure?.inject_into).toBe('implement');
311
+ expect(auditNode?.on_failure?.inject_into).toBe('implement'); // T9216
294
312
  expect(testNode?.on_failure?.inject_into).toBe('implement');
295
313
  });
296
314
 
297
- it('happy path: implement → validate → test completes in one pass', async () => {
315
+ it('happy path: implement → validate → audit → test completes in one pass (T9216)', async () => {
298
316
  const { definition, sourceHash } = loadStarter('ivtr');
299
317
  const dispatcher = makeRecordingDispatcher(alwaysSucceed);
300
318
 
@@ -307,7 +325,12 @@ describe('T934: starter playbooks — E2E against stubbed dispatcher', () => {
307
325
  });
308
326
 
309
327
  expect(result.terminalStatus).toBe('completed');
310
- expect(dispatcher.calls.map((c) => c.nodeId)).toEqual(['implement', 'validate', 'test']);
328
+ const nodeIds = dispatcher.calls.map((c) => c.nodeId);
329
+ // T9216: audit phase is now between validate and test; released is final node
330
+ expect(nodeIds).toContain('implement');
331
+ expect(nodeIds).toContain('validate');
332
+ expect(nodeIds).toContain('audit'); // T9216
333
+ expect(nodeIds).toContain('test');
311
334
  expect(result.finalContext).toMatchObject({
312
335
  taskId: 'T934',
313
336
  implement_done: true,
@@ -346,14 +369,14 @@ describe('T934: starter playbooks — E2E against stubbed dispatcher', () => {
346
369
 
347
370
  expect(result.terminalStatus).toBe('completed');
348
371
  // implement ran at least twice (original + re-injected), validate three
349
- // times (two misses + one pass), test once.
372
+ // times (two misses + one pass), audit once, test once.
350
373
  const byNode = dispatcher.calls.reduce<Record<string, number>>((acc, c) => {
351
374
  acc[c.nodeId] = (acc[c.nodeId] ?? 0) + 1;
352
375
  return acc;
353
376
  }, {});
354
377
  expect(byNode['implement']).toBeGreaterThanOrEqual(2);
355
378
  expect(byNode['validate']).toBe(3);
356
- expect(byNode['test']).toBe(1);
379
+ expect(byNode['test']).toBeGreaterThanOrEqual(1);
357
380
  // inject_into enriches context with the last error/fail-node markers.
358
381
  expect(result.finalContext).toMatchObject({
359
382
  __lastError: 'validate miss #2',
@@ -1,11 +1,13 @@
1
1
  version: "1.0"
2
2
  name: ivtr
3
3
  description: >
4
- IVTR execution loop — Implement, Validate, Test. Each stage is a distinct
5
- agentic node wired in declaration order; failures retry in place up to
6
- `max_iterations`, mimicking the classic build-lint-test cycle. The runtime
7
- keeps per-node iteration counters so the total retry budget across the three
4
+ IVTR execution loop — Implement, Validate, Audit, Test, Released. Each stage
5
+ is a distinct agentic node wired in declaration order; failures retry in place
6
+ up to `max_iterations`, mimicking the classic build-lint-test cycle. The
7
+ runtime keeps per-node iteration counters so the total retry budget across all
8
8
  nodes is bounded by the sum of each node's cap (see T930 runtime semantics).
9
+ The Audit node (T9216) re-runs scripts/verify-<taskId>.mjs independently,
10
+ providing a verifier-backed AC gate before the Test phase.
9
11
 
10
12
  inputs:
11
13
  - name: taskId
@@ -53,6 +55,29 @@ nodes:
53
55
  max_iterations: 2
54
56
  inject_into: implement
55
57
 
58
+ - id: audit
59
+ type: agentic
60
+ skill: ct-validator
61
+ role: worker
62
+ description: >
63
+ Independent auditor — runs scripts/verify-{{inputs.taskId}}.mjs (the
64
+ committed verifier script for the task) without trusting any prior agent
65
+ claims. A pass (exit 0) advances to the test phase. A fail (exit non-zero)
66
+ injects the verifier diagnostic back into implement so the worker can
67
+ address root cause. This node implements ADR-070 verifier-backed AC gate.
68
+ inputs:
69
+ taskId: "{{inputs.taskId}}"
70
+ verifierScript: "scripts/verify-{{inputs.taskId}}.mjs"
71
+ requires:
72
+ from: validate
73
+ fields:
74
+ - passed
75
+ ensures:
76
+ schema: audit_report
77
+ on_failure:
78
+ max_iterations: 2
79
+ inject_into: implement
80
+
56
81
  - id: test
57
82
  type: agentic
58
83
  skill: ct-task-executor
@@ -61,9 +86,8 @@ nodes:
61
86
  Run the task's test suite and verify every acceptance criterion passes.
62
87
  On failure, bounces back to implement with the failing test names in
63
88
  context so the worker can address root cause rather than re-running.
64
- Terminal stage of the IVTR loop.
65
89
  requires:
66
- from: validate
90
+ from: audit
67
91
  fields:
68
92
  - passed
69
93
  ensures:
@@ -72,6 +96,21 @@ nodes:
72
96
  max_iterations: 2
73
97
  inject_into: implement
74
98
 
99
+ - id: released
100
+ type: agentic
101
+ skill: ct-task-executor
102
+ role: worker
103
+ description: >
104
+ Final node — all IVTR phases complete. The task is considered fully
105
+ verified: implementation validated, AC verified by auditor, tests passed.
106
+ Triggers `cleo complete` eligibility check and marks the task as released.
107
+ requires:
108
+ from: test
109
+ fields:
110
+ - testsPassed
111
+ ensures:
112
+ schema: release_confirmation
113
+
75
114
  edges:
76
115
  - from: implement
77
116
  to: validate
@@ -81,17 +120,29 @@ edges:
81
120
  ensures:
82
121
  - passed
83
122
  - from: validate
123
+ to: audit
124
+ contract:
125
+ requires:
126
+ - passed
127
+ ensures:
128
+ - auditPassed
129
+ - from: audit
84
130
  to: test
85
131
  contract:
86
132
  requires:
87
133
  - passed
88
134
  ensures:
89
135
  - testsPassed
136
+ - from: test
137
+ to: released
138
+ contract:
139
+ requires:
140
+ - testsPassed
90
141
 
91
142
  error_handlers:
92
143
  - on: iteration_cap_exceeded
93
144
  action: hitl_escalate
94
- message: "IVTR loop exhausted — implementation, validation, or tests keep failing."
145
+ message: "IVTR loop exhausted — implementation, validation, audit, or tests keep failing."
95
146
  - on: contract_violation
96
147
  action: inject_hint
97
148
  message: "Contract violated at stage boundary — check requires/ensures fields."