cclaw-cli 6.1.0 → 6.1.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.
@@ -149,7 +149,10 @@ export declare function checkMandatoryDelegations(projectRoot: string, stage: Fl
149
149
  * Optional task class for the active run. When set to
150
150
  * `"software-bugfix"`, the mandatory delegation gate is skipped
151
151
  * entirely (Wave 24). Callers that don't classify the run leave
152
- * this undefined and rely on the track-based skip.
152
+ * this undefined; the function then falls back to
153
+ * `flowState.taskClass` (persisted in `flow-state.json`) so the
154
+ * Wave 24 bugfix-skip remains active across the `cclaw advance-stage`
155
+ * code path even when no caller forwards an explicit override.
153
156
  */
154
157
  taskClass?: MandatoryDelegationTaskClass | null;
155
158
  }): Promise<{
@@ -473,14 +473,22 @@ export async function checkMandatoryDelegations(projectRoot, stage, options = {}
473
473
  const flowState = await readFlowState(projectRoot, {
474
474
  repairFeatureSystem: options.repairFeatureSystem
475
475
  });
476
- const mandatory = mandatoryAgentsFor(stage, flowState.track, options.taskClass ?? null);
476
+ // Wave 24 follow-up (v6.1.1): read `flowState.taskClass` as a fallback
477
+ // when the caller doesn't pass an explicit override. The
478
+ // `cclaw advance-stage` path (`buildValidationReport` →
479
+ // `checkMandatoryDelegations`) never forwarded `taskClass`, which left
480
+ // the `software-bugfix` skip dead for users who classified their run
481
+ // via `flow-state.json`. Forward-typed `null` callers still suppress
482
+ // the lookup explicitly; only `undefined` triggers the fallback.
483
+ const resolvedTaskClass = options.taskClass !== undefined ? options.taskClass : flowState.taskClass ?? null;
484
+ const mandatory = mandatoryAgentsFor(stage, flowState.track, resolvedTaskClass);
477
485
  const skippedByTrack = mandatory.length === 0 &&
478
486
  stageSchema(stage, flowState.track).mandatoryDelegations.length > 0;
479
487
  if (skippedByTrack) {
480
488
  await recordMandatorySkippedByTrack(projectRoot, {
481
489
  stage,
482
490
  track: flowState.track,
483
- taskClass: options.taskClass ?? null,
491
+ taskClass: resolvedTaskClass,
484
492
  runId: flowState.activeRunId
485
493
  });
486
494
  }
@@ -160,7 +160,15 @@ export async function tryAutoHydrateAndSelectReviewLoopGate(projectRoot, stage,
160
160
  return [...selectedGateIds, gateId];
161
161
  }
162
162
  export async function buildValidationReport(projectRoot, flowState, options = {}) {
163
- const delegation = await checkMandatoryDelegations(projectRoot, flowState.currentStage);
163
+ // Wave 24 follow-up (v6.1.1): forward `flowState.taskClass` so the
164
+ // bugfix-skip lights up via the `cclaw advance-stage` path. The
165
+ // delegation helper now has its own fallback (it reads `flowState`
166
+ // internally), but threading the value here keeps the call site
167
+ // self-documenting and survives any future refactor that drops the
168
+ // implicit fallback.
169
+ const delegation = await checkMandatoryDelegations(projectRoot, flowState.currentStage, {
170
+ taskClass: flowState.taskClass ?? undefined
171
+ });
164
172
  const gates = await verifyCurrentStageGateEvidence(projectRoot, flowState, {
165
173
  extraStageFlags: options.extraStageFlags
166
174
  });
@@ -159,6 +159,29 @@ function sanitizeStageGateCatalog(value, fallback) {
159
159
  function coerceTrack(value) {
160
160
  return isFlowTrack(value) ? value : "standard";
161
161
  }
162
+ /**
163
+ * Wave 24 follow-up (v6.1.1) — preserve `flow-state.json#taskClass`
164
+ * across read/write round-trips. Before this audit fix the persistence
165
+ * layer silently dropped the field, which made the Wave 24 bugfix-skip
166
+ * (`mandatoryAgentsFor` short-circuit) and the Wave 25 artifact-validation
167
+ * demotion both dead in practice: the only entry point that classified
168
+ * a run was the unit-test harness passing `options.taskClass` directly
169
+ * to `checkMandatoryDelegations`. The accepted union mirrors
170
+ * `MandatoryDelegationTaskClass` plus `null` so callers can explicitly
171
+ * clear the classification without dropping the property.
172
+ */
173
+ function coerceTaskClass(value) {
174
+ if (value === undefined)
175
+ return undefined;
176
+ if (value === null)
177
+ return null;
178
+ if (value === "software-standard" ||
179
+ value === "software-trivial" ||
180
+ value === "software-bugfix") {
181
+ return value;
182
+ }
183
+ return undefined;
184
+ }
162
185
  function sanitizeSkippedStages(value, track) {
163
186
  const trackDefault = skippedStagesForTrack(track);
164
187
  if (!Array.isArray(value)) {
@@ -354,6 +377,7 @@ function coerceFlowState(parsed) {
354
377
  const activeRunId = typeof activeRunIdRaw === "string" && activeRunIdRaw.trim().length > 0
355
378
  ? activeRunIdRaw.trim()
356
379
  : next.activeRunId;
380
+ const taskClass = coerceTaskClass(parsed.taskClass);
357
381
  const state = {
358
382
  schemaVersion: FLOW_STATE_SCHEMA_VERSION,
359
383
  activeRunId,
@@ -362,6 +386,7 @@ function coerceFlowState(parsed) {
362
386
  guardEvidence: sanitizeGuardEvidence(parsed.guardEvidence),
363
387
  stageGateCatalog: sanitizeStageGateCatalog(parsed.stageGateCatalog, next.stageGateCatalog),
364
388
  track,
389
+ ...(taskClass !== undefined ? { taskClass } : {}),
365
390
  skippedStages: sanitizeSkippedStages(parsed.skippedStages, track),
366
391
  staleStages: sanitizeStaleStages(parsed.staleStages),
367
392
  rewinds: sanitizeRewinds(parsed.rewinds),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cclaw-cli",
3
- "version": "6.1.0",
3
+ "version": "6.1.1",
4
4
  "description": "Installer-first flow toolkit for coding agents",
5
5
  "type": "module",
6
6
  "bin": {