@claude-flow/cli 3.32.25 → 3.32.26

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.
@@ -11,10 +11,9 @@
11
11
  * 4. GATE the winner through the shipped runHarnessLoop on the HELD-OUT split:
12
12
  * held_out_improves AND redblue(anchor-no-regress) AND drift<=thr AND
13
13
  * replay-deterministic AND receipt_coverage AND canary-no-worse.
14
- * 5. On accept → APPLY locally (the install self-optimizes on its own data; no
15
- * signing needed because nothing is propagated), CHAIN to the previous
16
- * champion, and record the attempt in the improvement ledger. Also STAGE
17
- * the unsigned champion for optional promotion to the signed global channel.
14
+ * 5. On accept → emit + persist an immutable evaluation receipt. Evaluation
15
+ * never mutates active policy. Explicit promotion is handled by the
16
+ * ADR-322A transaction service.
18
17
  *
19
18
  * Trust split: LOCAL self-optimization is unsigned (an install trusting its own
20
19
  * measured gate); CROSS-install propagation still requires the config-signed
@@ -27,6 +26,8 @@ import { hashCorpus } from './harness-benchmark.js';
27
26
  import { harvestSelfSupervisedTasks, blendCorpus } from './harness-corpus-harvester.js';
28
27
  import { applyChampionParams } from '../config/harness-feedback-applier.js';
29
28
  import { appendLedger, bootstrapDeltaCILow } from './harness-improvement-ledger.js';
29
+ import { createFlywheelReceipt, sha256Ref, } from './flywheel-receipt.js';
30
+ import { readFlywheelTransactionState, registerFlywheelReceipt, } from './flywheel-transaction.js';
30
31
  export const DEFAULT_CONFIG = { alpha: 0.5, subjectWeight: 2.0, mmrLambda: 0.7, bodyWeight: 1.0, typePenaltyFactor: 1.0 };
31
32
  const EPS = 1e-3;
32
33
  const cfgCanon = (c) => JSON.stringify(Object.fromEntries(Object.keys(c).sort().map((k) => [k, c[k]])));
@@ -50,7 +51,7 @@ function grade(ranked, expected) {
50
51
  const idx = ranked.findIndex((r) => r.id === expected);
51
52
  return idx >= 0 ? 1 / (idx + 1) : 0;
52
53
  }
53
- function neighbors(base) {
54
+ export function retrievalPolicyNeighbors(base) {
54
55
  const steps = { alpha: 0.1, subjectWeight: 0.5, mmrLambda: 0.1, bodyWeight: 0.5, typePenaltyFactor: 0.25 };
55
56
  const out = [];
56
57
  const seen = new Set();
@@ -89,7 +90,7 @@ function split(tasks, frac) {
89
90
  * Returns a rich result AND (as a side effect) appends to the improvement ledger
90
91
  * and — on accept — applies the champion locally + chains it.
91
92
  */
92
- export async function runFlywheelTick(projectRoot, deps) {
93
+ export async function evaluateFlywheelCandidate(projectRoot, deps) {
93
94
  try {
94
95
  const patterns = await deps.getPatterns();
95
96
  if (!patterns || patterns.length < 8)
@@ -100,7 +101,9 @@ export async function runFlywheelTick(projectRoot, deps) {
100
101
  const blended = blendCorpus(deps.anchorTasks, harvested);
101
102
  const anchorIdSet = new Set(blended.anchorIds);
102
103
  const baseline = { ...DEFAULT_CONFIG, ...(deps.activeParams?.() ?? {}) };
103
- const candidates = neighbors(baseline);
104
+ const candidates = deps.candidatePolicies?.length
105
+ ? deps.candidatePolicies.map((candidate) => ({ ...candidate }))
106
+ : retrievalPolicyNeighbors(baseline);
104
107
  // OBJECTIVE = the human-labeled anchor (the relevance we actually care about,
105
108
  // where headroom is known to exist). GUARD = the large, growing harvested set
106
109
  // (don't wreck broad retrieval while tuning the objective). Optimize the
@@ -171,7 +174,76 @@ export async function runFlywheelTick(projectRoot, deps) {
171
174
  const heldDeltas = held.map((t) => heldScoreFor(candidate, t) - heldScoreFor(baseline, t));
172
175
  const deltaCILow = bootstrapDeltaCILow(heldDeltas);
173
176
  const significant = deltaCILow > 0;
174
- const finalAccept = result.accepted && significant;
177
+ const provisionalGates = Object.fromEntries(Object.entries(result.verdict?.terms ?? {}).map(([k, v]) => [k, v.pass]));
178
+ const txState = readFlywheelTransactionState(projectRoot);
179
+ const safetyEnvelopeRef = deps.safetyEnvelopeRef ?? sha256Ref(JSON.stringify({
180
+ schema: 'ruflo.safety-envelope/local-default-v1',
181
+ authorizationExpansion: false,
182
+ networkExpansion: false,
183
+ spendExpansion: false,
184
+ }));
185
+ const receipt = createFlywheelReceipt({
186
+ lineageId: deps.lineageId,
187
+ evaluationRunId: deps.evaluationRunId,
188
+ baselineRef: refOf(baseline),
189
+ expectedLedgerHead: txState.ledgerHead,
190
+ candidatePolicy: candidate,
191
+ safetyEnvelopeRef,
192
+ requestedProposer: deps.requestedProposer ?? 'local',
193
+ effectiveProposer: deps.effectiveProposer ?? 'local',
194
+ proposerSubstitution: deps.proposerSubstitution,
195
+ corpusVersion: blended.version,
196
+ corpusHash: blended.corpusHash,
197
+ baselineScore,
198
+ candidateScore,
199
+ heldOutDeltas: heldDeltas,
200
+ frozenAnchorRegression: guardRegressed ? 1 : 0,
201
+ gates: provisionalGates,
202
+ resourceEvidence: {
203
+ p95LatencyMicros: 0,
204
+ costMicrosPerTask: 0,
205
+ tokensPerTask: 0,
206
+ failureRate: '0',
207
+ evaluationCostMicros: 0,
208
+ currency: 'USD',
209
+ },
210
+ evidence: {
211
+ corpusRoles: {
212
+ selectionTaskIds: train.map((task) => task.id),
213
+ promotionHoldoutTaskIds: held.map((task) => task.id),
214
+ guardTaskIds: guard.map((task) => task.id),
215
+ },
216
+ verification: {
217
+ redblue: result.verify?.redblue ?? 'SKIPPED',
218
+ drift: result.verify?.drift ?? -1,
219
+ driftThreshold: result.verify?.driftThreshold ?? 0.2,
220
+ driftVerdict: result.verify?.driftVerdict ?? 'skipped',
221
+ adversarialPass: result.verify?.adversarialPass ?? false,
222
+ },
223
+ canary: {
224
+ candidate: result.canary?.candidate ?? {},
225
+ baseline: result.canary?.baseline ?? {},
226
+ pass: result.canary?.pass ?? false,
227
+ },
228
+ },
229
+ termVerification: Object.keys(provisionalGates).map((term) => ({
230
+ term,
231
+ verification: 'recomputed',
232
+ evidenceRef: sha256Ref(JSON.stringify({
233
+ term,
234
+ corpusHash: blended.corpusHash,
235
+ heldOutDeltas: heldDeltas,
236
+ verification: result.verify,
237
+ canary: result.canary,
238
+ })),
239
+ })),
240
+ now: deps.now,
241
+ privateKeyPem: deps.receiptPrivateKeyPem,
242
+ publicKeyPem: deps.receiptPublicKeyPem,
243
+ bootstrapIterations: deps.bootstrapIterations,
244
+ });
245
+ await registerFlywheelReceipt(projectRoot, receipt, deps.now ?? Date.now());
246
+ const finalAccept = result.accepted && significant && receipt.payload.decision === 'accepted';
175
247
  const entry = {
176
248
  ts: deps.now ?? Date.now(),
177
249
  corpusVersion: blended.version, corpusHash: blended.corpusHash,
@@ -180,28 +252,46 @@ export async function runFlywheelTick(projectRoot, deps) {
180
252
  baselineScore, candidateScore, delta: candidateScore - baselineScore,
181
253
  deltaCILow, significant, loopAccepted: result.accepted,
182
254
  anchorRegressed, accepted: finalAccept,
183
- gates: Object.fromEntries(Object.entries(result.verdict?.terms ?? {}).map(([k, v]) => [k, v.pass])),
255
+ gates: provisionalGates,
184
256
  reason: finalAccept ? result.reason : (result.accepted ? `held back — improvement not significant (CI low ${deltaCILow.toFixed(4)})` : result.reason),
185
257
  };
186
- let applied = false;
187
- if (finalAccept && result.manifest) {
188
- entry.championRef = refOf(candidate);
189
- // Apply locally (self-optimization) + chain to the previous champion.
190
- const ap = applyChampionParams(projectRoot, {
191
- championId: refOf(candidate), params: candidate,
192
- layer: 'repo/local', previous: refOf(baseline), now: deps.now,
193
- });
194
- applied = ap.applied;
195
- }
196
258
  appendLedger(`${projectRoot}/.claude-flow/metrics`, entry);
197
259
  return {
198
- ran: true, reason: entry.reason, accepted: finalAccept, applied,
260
+ ran: true, reason: entry.reason, accepted: finalAccept, applied: false,
199
261
  baselineScore, candidateScore, delta: candidateScore - baselineScore,
200
- anchorRegressed, championRef: entry.championRef, corpusVersion: blended.version,
262
+ anchorRegressed, championRef: finalAccept ? refOf(candidate) : undefined,
263
+ corpusVersion: blended.version, candidateConfig: candidate,
264
+ receiptId: receipt.payload.receiptId, receipt, promotable: finalAccept && !!receipt.signature,
201
265
  };
202
266
  }
203
267
  catch (e) {
204
268
  return { ran: false, reason: `error: ${e?.message ?? e}` };
205
269
  }
206
270
  }
271
+ /**
272
+ * Compatibility wrapper. New callers get evaluation-only semantics. The legacy
273
+ * implicit apply path exists for one release behind an explicit opt-in flag.
274
+ */
275
+ export async function runFlywheelTick(projectRoot, deps) {
276
+ const result = await evaluateFlywheelCandidate(projectRoot, deps);
277
+ if (process.env.RUFLO_FLYWHEEL_LEGACY_APPLY === '1'
278
+ && result.accepted
279
+ && result.candidateConfig
280
+ && result.championRef) {
281
+ const applied = applyChampionParams(projectRoot, {
282
+ championId: result.championRef,
283
+ params: result.candidateConfig,
284
+ layer: 'repo/local',
285
+ previous: result.receipt?.payload.baselineRef,
286
+ now: deps.now,
287
+ });
288
+ return {
289
+ ...result,
290
+ applied: applied.applied,
291
+ legacyDeprecation: true,
292
+ reason: `${result.reason}; deprecated implicit apply path`,
293
+ };
294
+ }
295
+ return result;
296
+ }
207
297
  //# sourceMappingURL=harness-flywheel.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claude-flow/cli",
3
- "version": "3.32.25",
3
+ "version": "3.32.26",
4
4
  "type": "module",
5
5
  "description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",
@@ -86,6 +86,7 @@
86
86
  ],
87
87
  "scripts": {
88
88
  "build": "tsc",
89
+ "check:metaharness-pins": "node ../../../scripts/check-metaharness-pins.mjs",
89
90
  "test": "vitest run",
90
91
  "test:plugin-store": "npx tsx src/plugins/tests/standalone-test.ts",
91
92
  "test:pattern-store": "npx tsx src/transfer/store/tests/standalone-test.ts",
@@ -116,6 +117,7 @@
116
117
  "@claude-flow/memory": "^3.0.0-alpha.21",
117
118
  "@claude-flow/security": "^3.0.0-alpha.12",
118
119
  "@metaharness/darwin": "^0.8.0",
120
+ "@metaharness/flywheel": "^0.1.7",
119
121
  "agentdb": "^3.0.0-alpha.17",
120
122
  "agentic-flow": "^3.0.0-alpha.1",
121
123
  "better-sqlite3": "^12.9.0",
@@ -1 +0,0 @@
1
- sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319
@@ -1,42 +0,0 @@
1
- {
2
- "adoptedAt": 1785250806308,
3
- "championId": "sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319",
4
- "manifest": {
5
- "schema": "ruflo.proven-config/v1",
6
- "policy": {
7
- "ref": "sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319",
8
- "value": {
9
- "alpha": 0.3,
10
- "subjectWeight": 1,
11
- "mmrLambda": 0.5,
12
- "bodyWeight": 1.5,
13
- "typePenaltyFactor": 0.5
14
- }
15
- },
16
- "layer": "framework/node-cli",
17
- "compatibility": {
18
- "ruflo": ">=3.24.0"
19
- },
20
- "benchmark": {
21
- "corpus": "ADR-081-labelled-v1",
22
- "corpusHash": "sha256:2f700b5c363e20a3bd88ce2bc9b87bbbbaa61732c6177894c6ec37890f888982"
23
- },
24
- "receipt": {
25
- "heldOutDelta": 0.07381404928570845,
26
- "redblue": "PASS",
27
- "drift": 0,
28
- "canary": {
29
- "rollbackRate": 0,
30
- "latencyP95": 244.612458000076,
31
- "costPerTask": 0
32
- },
33
- "receiptCoverage": 1
34
- },
35
- "platform": [
36
- "linux",
37
- "macOS",
38
- "windows"
39
- ]
40
- },
41
- "previous": ""
42
- }