cclaw-cli 7.5.0 → 7.7.0
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/README.md +2 -1
- package/dist/artifact-linter/plan.js +238 -26
- package/dist/artifact-linter/tdd.js +4 -3
- package/dist/config.d.ts +18 -1
- package/dist/config.js +176 -5
- package/dist/content/core-agents.d.ts +1 -1
- package/dist/content/core-agents.js +17 -2
- package/dist/content/hooks.js +37 -0
- package/dist/content/meta-skill.js +4 -4
- package/dist/content/skills.js +12 -8
- package/dist/content/stage-schema.js +3 -2
- package/dist/content/stages/plan.js +18 -17
- package/dist/content/stages/tdd.js +13 -10
- package/dist/content/start-command.js +3 -3
- package/dist/content/subagent-context-skills.js +2 -2
- package/dist/content/subagents.js +6 -6
- package/dist/content/templates.js +12 -7
- package/dist/delegation.d.ts +43 -3
- package/dist/delegation.js +80 -9
- package/dist/execution-topology.d.ts +36 -0
- package/dist/execution-topology.js +73 -0
- package/dist/gate-evidence.js +10 -12
- package/dist/internal/advance-stage/start-flow.js +13 -4
- package/dist/internal/cohesion-contract-stub.js +2 -14
- package/dist/internal/plan-split-waves.d.ts +5 -2
- package/dist/internal/plan-split-waves.js +27 -16
- package/dist/internal/slice-commit.js +161 -7
- package/dist/internal/wave-status.d.ts +4 -0
- package/dist/internal/wave-status.js +50 -9
- package/dist/stack-detection.d.ts +94 -0
- package/dist/stack-detection.js +431 -0
- package/dist/tdd-cycle.js +7 -5
- package/dist/types.d.ts +67 -0
- package/dist/util/slice-id.d.ts +58 -0
- package/dist/util/slice-id.js +89 -0
- package/package.json +1 -1
package/dist/config.js
CHANGED
|
@@ -6,7 +6,14 @@ import { exists, writeFileSafe } from "./fs-utils.js";
|
|
|
6
6
|
import { HARNESS_IDS } from "./types.js";
|
|
7
7
|
const CONFIG_PATH = `${RUNTIME_ROOT}/config.yaml`;
|
|
8
8
|
const HARNESS_ID_SET = new Set(HARNESS_IDS);
|
|
9
|
-
const ALLOWED_CONFIG_KEYS = new Set([
|
|
9
|
+
const ALLOWED_CONFIG_KEYS = new Set([
|
|
10
|
+
"version",
|
|
11
|
+
"flowVersion",
|
|
12
|
+
"harnesses",
|
|
13
|
+
"tdd",
|
|
14
|
+
"execution",
|
|
15
|
+
"plan"
|
|
16
|
+
]);
|
|
10
17
|
const SUPPORTED_HARNESSES_TEXT = HARNESS_IDS.join(", ");
|
|
11
18
|
export const TDD_COMMIT_MODES = [
|
|
12
19
|
"managed-per-slice",
|
|
@@ -20,6 +27,28 @@ export const TDD_ISOLATION_MODES = ["worktree", "in-place", "auto"];
|
|
|
20
27
|
const TDD_ISOLATION_MODE_SET = new Set(TDD_ISOLATION_MODES);
|
|
21
28
|
export const DEFAULT_TDD_ISOLATION_MODE = "worktree";
|
|
22
29
|
export const DEFAULT_TDD_WORKTREE_ROOT = `${RUNTIME_ROOT}/worktrees`;
|
|
30
|
+
export const LOCKFILE_TWIN_POLICIES = ["auto-include", "auto-revert", "strict-fence"];
|
|
31
|
+
const LOCKFILE_TWIN_POLICY_SET = new Set(LOCKFILE_TWIN_POLICIES);
|
|
32
|
+
export const DEFAULT_LOCKFILE_TWIN_POLICY = "auto-include";
|
|
33
|
+
export const EXECUTION_TOPOLOGIES = [
|
|
34
|
+
"auto",
|
|
35
|
+
"inline",
|
|
36
|
+
"single-builder",
|
|
37
|
+
"parallel-builders",
|
|
38
|
+
"strict-micro"
|
|
39
|
+
];
|
|
40
|
+
const EXECUTION_TOPOLOGY_SET = new Set(EXECUTION_TOPOLOGIES);
|
|
41
|
+
export const DEFAULT_EXECUTION_TOPOLOGY = "auto";
|
|
42
|
+
export const EXECUTION_STRICTNESS_PROFILES = ["fast", "balanced", "strict"];
|
|
43
|
+
const EXECUTION_STRICTNESS_PROFILE_SET = new Set(EXECUTION_STRICTNESS_PROFILES);
|
|
44
|
+
export const DEFAULT_EXECUTION_STRICTNESS = "balanced";
|
|
45
|
+
export const DEFAULT_MAX_BUILDERS = 5;
|
|
46
|
+
export const PLAN_SLICE_GRANULARITIES = ["feature-atomic", "strict-micro"];
|
|
47
|
+
const PLAN_SLICE_GRANULARITY_SET = new Set(PLAN_SLICE_GRANULARITIES);
|
|
48
|
+
export const DEFAULT_PLAN_SLICE_GRANULARITY = "feature-atomic";
|
|
49
|
+
export const PLAN_MICRO_TASK_POLICIES = ["advisory", "strict"];
|
|
50
|
+
const PLAN_MICRO_TASK_POLICY_SET = new Set(PLAN_MICRO_TASK_POLICIES);
|
|
51
|
+
export const DEFAULT_PLAN_MICRO_TASK_POLICY = "advisory";
|
|
23
52
|
// Kept for runtime modules that use these defaults directly.
|
|
24
53
|
export const DEFAULT_TDD_TEST_PATH_PATTERNS = [
|
|
25
54
|
"**/*.test.*",
|
|
@@ -46,7 +75,14 @@ function configFixExample() {
|
|
|
46
75
|
tdd:
|
|
47
76
|
commitMode: managed-per-slice
|
|
48
77
|
isolationMode: worktree
|
|
49
|
-
worktreeRoot: .cclaw/worktrees
|
|
78
|
+
worktreeRoot: .cclaw/worktrees
|
|
79
|
+
execution:
|
|
80
|
+
topology: auto
|
|
81
|
+
strictness: balanced
|
|
82
|
+
maxBuilders: 5
|
|
83
|
+
plan:
|
|
84
|
+
sliceGranularity: feature-atomic
|
|
85
|
+
microTaskPolicy: advisory`;
|
|
50
86
|
}
|
|
51
87
|
function configValidationError(configFilePath, reason) {
|
|
52
88
|
return new InvalidConfigError(`Invalid cclaw config at ${configFilePath}: ${reason}\n` +
|
|
@@ -68,7 +104,17 @@ export function createDefaultConfig(harnesses = DEFAULT_HARNESSES, _defaultTrack
|
|
|
68
104
|
tdd: {
|
|
69
105
|
commitMode: DEFAULT_TDD_COMMIT_MODE,
|
|
70
106
|
isolationMode: DEFAULT_TDD_ISOLATION_MODE,
|
|
71
|
-
worktreeRoot: DEFAULT_TDD_WORKTREE_ROOT
|
|
107
|
+
worktreeRoot: DEFAULT_TDD_WORKTREE_ROOT,
|
|
108
|
+
lockfileTwinPolicy: DEFAULT_LOCKFILE_TWIN_POLICY
|
|
109
|
+
},
|
|
110
|
+
execution: {
|
|
111
|
+
topology: DEFAULT_EXECUTION_TOPOLOGY,
|
|
112
|
+
strictness: DEFAULT_EXECUTION_STRICTNESS,
|
|
113
|
+
maxBuilders: DEFAULT_MAX_BUILDERS
|
|
114
|
+
},
|
|
115
|
+
plan: {
|
|
116
|
+
sliceGranularity: DEFAULT_PLAN_SLICE_GRANULARITY,
|
|
117
|
+
microTaskPolicy: DEFAULT_PLAN_MICRO_TASK_POLICY
|
|
72
118
|
}
|
|
73
119
|
};
|
|
74
120
|
}
|
|
@@ -93,6 +139,48 @@ export function resolveTddWorktreeRoot(config) {
|
|
|
93
139
|
}
|
|
94
140
|
return DEFAULT_TDD_WORKTREE_ROOT;
|
|
95
141
|
}
|
|
142
|
+
export function resolveLockfileTwinPolicy(config) {
|
|
143
|
+
const raw = config?.tdd?.lockfileTwinPolicy;
|
|
144
|
+
if (typeof raw === "string" && LOCKFILE_TWIN_POLICY_SET.has(raw)) {
|
|
145
|
+
return raw;
|
|
146
|
+
}
|
|
147
|
+
return DEFAULT_LOCKFILE_TWIN_POLICY;
|
|
148
|
+
}
|
|
149
|
+
export function resolveExecutionTopology(config) {
|
|
150
|
+
const raw = config?.execution?.topology;
|
|
151
|
+
if (typeof raw === "string" && EXECUTION_TOPOLOGY_SET.has(raw)) {
|
|
152
|
+
return raw;
|
|
153
|
+
}
|
|
154
|
+
return DEFAULT_EXECUTION_TOPOLOGY;
|
|
155
|
+
}
|
|
156
|
+
export function resolveExecutionStrictness(config) {
|
|
157
|
+
const raw = config?.execution?.strictness;
|
|
158
|
+
if (typeof raw === "string" && EXECUTION_STRICTNESS_PROFILE_SET.has(raw)) {
|
|
159
|
+
return raw;
|
|
160
|
+
}
|
|
161
|
+
return DEFAULT_EXECUTION_STRICTNESS;
|
|
162
|
+
}
|
|
163
|
+
export function resolveMaxBuilders(config) {
|
|
164
|
+
const raw = config?.execution?.maxBuilders;
|
|
165
|
+
if (typeof raw === "number" && Number.isInteger(raw) && raw >= 1) {
|
|
166
|
+
return raw;
|
|
167
|
+
}
|
|
168
|
+
return DEFAULT_MAX_BUILDERS;
|
|
169
|
+
}
|
|
170
|
+
export function resolvePlanSliceGranularity(config) {
|
|
171
|
+
const raw = config?.plan?.sliceGranularity;
|
|
172
|
+
if (typeof raw === "string" && PLAN_SLICE_GRANULARITY_SET.has(raw)) {
|
|
173
|
+
return raw;
|
|
174
|
+
}
|
|
175
|
+
return DEFAULT_PLAN_SLICE_GRANULARITY;
|
|
176
|
+
}
|
|
177
|
+
export function resolvePlanMicroTaskPolicy(config) {
|
|
178
|
+
const raw = config?.plan?.microTaskPolicy;
|
|
179
|
+
if (typeof raw === "string" && PLAN_MICRO_TASK_POLICY_SET.has(raw)) {
|
|
180
|
+
return raw;
|
|
181
|
+
}
|
|
182
|
+
return DEFAULT_PLAN_MICRO_TASK_POLICY;
|
|
183
|
+
}
|
|
96
184
|
function assertOnlySupportedKeys(parsed, fullPath) {
|
|
97
185
|
const unknownKeys = Object.keys(parsed).filter((key) => !ALLOWED_CONFIG_KEYS.has(key));
|
|
98
186
|
if (unknownKeys.length === 0)
|
|
@@ -130,6 +218,14 @@ export async function readConfig(projectRoot, _options = {}) {
|
|
|
130
218
|
!isRecord(parsed.tdd)) {
|
|
131
219
|
throw configValidationError(fullPath, `"tdd" must be an object when provided`);
|
|
132
220
|
}
|
|
221
|
+
if (Object.prototype.hasOwnProperty.call(parsed, "execution") &&
|
|
222
|
+
!isRecord(parsed.execution)) {
|
|
223
|
+
throw configValidationError(fullPath, `"execution" must be an object when provided`);
|
|
224
|
+
}
|
|
225
|
+
if (Object.prototype.hasOwnProperty.call(parsed, "plan") &&
|
|
226
|
+
!isRecord(parsed.plan)) {
|
|
227
|
+
throw configValidationError(fullPath, `"plan" must be an object when provided`);
|
|
228
|
+
}
|
|
133
229
|
const rawHarnesses = Array.isArray(parsed.harnesses) ? parsed.harnesses : DEFAULT_HARNESSES;
|
|
134
230
|
const normalizedHarnesses = [];
|
|
135
231
|
for (const harness of rawHarnesses) {
|
|
@@ -153,6 +249,14 @@ export async function readConfig(projectRoot, _options = {}) {
|
|
|
153
249
|
const rawCommitMode = parsedTdd.commitMode;
|
|
154
250
|
const rawIsolationMode = parsedTdd.isolationMode;
|
|
155
251
|
const rawWorktreeRoot = parsedTdd.worktreeRoot;
|
|
252
|
+
const rawLockfileTwinPolicy = parsedTdd.lockfileTwinPolicy;
|
|
253
|
+
const parsedExecution = isRecord(parsed.execution) ? parsed.execution : {};
|
|
254
|
+
const rawExecutionTopology = parsedExecution.topology;
|
|
255
|
+
const rawExecutionStrictness = parsedExecution.strictness;
|
|
256
|
+
const rawMaxBuilders = parsedExecution.maxBuilders;
|
|
257
|
+
const parsedPlan = isRecord(parsed.plan) ? parsed.plan : {};
|
|
258
|
+
const rawPlanSliceGranularity = parsedPlan.sliceGranularity;
|
|
259
|
+
const rawPlanMicroTaskPolicy = parsedPlan.microTaskPolicy;
|
|
156
260
|
if (rawCommitMode !== undefined &&
|
|
157
261
|
(typeof rawCommitMode !== "string" || !TDD_COMMIT_MODE_SET.has(rawCommitMode))) {
|
|
158
262
|
throw configValidationError(fullPath, `"tdd.commitMode" must be one of: ${TDD_COMMIT_MODES.join(", ")}`);
|
|
@@ -165,6 +269,33 @@ export async function readConfig(projectRoot, _options = {}) {
|
|
|
165
269
|
(typeof rawWorktreeRoot !== "string" || rawWorktreeRoot.trim().length === 0)) {
|
|
166
270
|
throw configValidationError(fullPath, `"tdd.worktreeRoot" must be a non-empty string when provided`);
|
|
167
271
|
}
|
|
272
|
+
if (rawLockfileTwinPolicy !== undefined &&
|
|
273
|
+
(typeof rawLockfileTwinPolicy !== "string" || !LOCKFILE_TWIN_POLICY_SET.has(rawLockfileTwinPolicy))) {
|
|
274
|
+
throw configValidationError(fullPath, `"tdd.lockfileTwinPolicy" must be one of: ${LOCKFILE_TWIN_POLICIES.join(", ")}`);
|
|
275
|
+
}
|
|
276
|
+
if (rawExecutionTopology !== undefined &&
|
|
277
|
+
(typeof rawExecutionTopology !== "string" || !EXECUTION_TOPOLOGY_SET.has(rawExecutionTopology))) {
|
|
278
|
+
throw configValidationError(fullPath, `"execution.topology" must be one of: ${EXECUTION_TOPOLOGIES.join(", ")}`);
|
|
279
|
+
}
|
|
280
|
+
if (rawExecutionStrictness !== undefined &&
|
|
281
|
+
(typeof rawExecutionStrictness !== "string" ||
|
|
282
|
+
!EXECUTION_STRICTNESS_PROFILE_SET.has(rawExecutionStrictness))) {
|
|
283
|
+
throw configValidationError(fullPath, `"execution.strictness" must be one of: ${EXECUTION_STRICTNESS_PROFILES.join(", ")}`);
|
|
284
|
+
}
|
|
285
|
+
if (rawMaxBuilders !== undefined &&
|
|
286
|
+
(!Number.isInteger(rawMaxBuilders) || rawMaxBuilders < 1)) {
|
|
287
|
+
throw configValidationError(fullPath, `"execution.maxBuilders" must be an integer >= 1 when provided`);
|
|
288
|
+
}
|
|
289
|
+
if (rawPlanSliceGranularity !== undefined &&
|
|
290
|
+
(typeof rawPlanSliceGranularity !== "string" ||
|
|
291
|
+
!PLAN_SLICE_GRANULARITY_SET.has(rawPlanSliceGranularity))) {
|
|
292
|
+
throw configValidationError(fullPath, `"plan.sliceGranularity" must be one of: ${PLAN_SLICE_GRANULARITIES.join(", ")}`);
|
|
293
|
+
}
|
|
294
|
+
if (rawPlanMicroTaskPolicy !== undefined &&
|
|
295
|
+
(typeof rawPlanMicroTaskPolicy !== "string" ||
|
|
296
|
+
!PLAN_MICRO_TASK_POLICY_SET.has(rawPlanMicroTaskPolicy))) {
|
|
297
|
+
throw configValidationError(fullPath, `"plan.microTaskPolicy" must be one of: ${PLAN_MICRO_TASK_POLICIES.join(", ")}`);
|
|
298
|
+
}
|
|
168
299
|
const commitMode = typeof rawCommitMode === "string"
|
|
169
300
|
? rawCommitMode
|
|
170
301
|
: DEFAULT_TDD_COMMIT_MODE;
|
|
@@ -174,6 +305,26 @@ export async function readConfig(projectRoot, _options = {}) {
|
|
|
174
305
|
const worktreeRoot = typeof rawWorktreeRoot === "string" && rawWorktreeRoot.trim().length > 0
|
|
175
306
|
? rawWorktreeRoot.trim()
|
|
176
307
|
: DEFAULT_TDD_WORKTREE_ROOT;
|
|
308
|
+
const lockfileTwinPolicy = typeof rawLockfileTwinPolicy === "string"
|
|
309
|
+
? rawLockfileTwinPolicy
|
|
310
|
+
: DEFAULT_LOCKFILE_TWIN_POLICY;
|
|
311
|
+
const executionTopology = typeof rawExecutionTopology === "string"
|
|
312
|
+
? rawExecutionTopology
|
|
313
|
+
: DEFAULT_EXECUTION_TOPOLOGY;
|
|
314
|
+
const executionStrictness = typeof rawExecutionStrictness === "string"
|
|
315
|
+
? rawExecutionStrictness
|
|
316
|
+
: DEFAULT_EXECUTION_STRICTNESS;
|
|
317
|
+
const maxBuilders = typeof rawMaxBuilders === "number" &&
|
|
318
|
+
Number.isInteger(rawMaxBuilders) &&
|
|
319
|
+
rawMaxBuilders >= 1
|
|
320
|
+
? rawMaxBuilders
|
|
321
|
+
: DEFAULT_MAX_BUILDERS;
|
|
322
|
+
const planSliceGranularity = typeof rawPlanSliceGranularity === "string"
|
|
323
|
+
? rawPlanSliceGranularity
|
|
324
|
+
: DEFAULT_PLAN_SLICE_GRANULARITY;
|
|
325
|
+
const planMicroTaskPolicy = typeof rawPlanMicroTaskPolicy === "string"
|
|
326
|
+
? rawPlanMicroTaskPolicy
|
|
327
|
+
: DEFAULT_PLAN_MICRO_TASK_POLICY;
|
|
177
328
|
return {
|
|
178
329
|
version,
|
|
179
330
|
flowVersion,
|
|
@@ -181,7 +332,17 @@ export async function readConfig(projectRoot, _options = {}) {
|
|
|
181
332
|
tdd: {
|
|
182
333
|
commitMode,
|
|
183
334
|
isolationMode,
|
|
184
|
-
worktreeRoot
|
|
335
|
+
worktreeRoot,
|
|
336
|
+
lockfileTwinPolicy
|
|
337
|
+
},
|
|
338
|
+
execution: {
|
|
339
|
+
topology: executionTopology,
|
|
340
|
+
strictness: executionStrictness,
|
|
341
|
+
maxBuilders
|
|
342
|
+
},
|
|
343
|
+
plan: {
|
|
344
|
+
sliceGranularity: planSliceGranularity,
|
|
345
|
+
microTaskPolicy: planMicroTaskPolicy
|
|
185
346
|
}
|
|
186
347
|
};
|
|
187
348
|
}
|
|
@@ -193,7 +354,17 @@ export async function writeConfig(projectRoot, config, _options = {}) {
|
|
|
193
354
|
tdd: {
|
|
194
355
|
commitMode: resolveTddCommitMode(config),
|
|
195
356
|
isolationMode: resolveTddIsolationMode(config),
|
|
196
|
-
worktreeRoot: resolveTddWorktreeRoot(config)
|
|
357
|
+
worktreeRoot: resolveTddWorktreeRoot(config),
|
|
358
|
+
lockfileTwinPolicy: resolveLockfileTwinPolicy(config)
|
|
359
|
+
},
|
|
360
|
+
execution: {
|
|
361
|
+
topology: resolveExecutionTopology(config),
|
|
362
|
+
strictness: resolveExecutionStrictness(config),
|
|
363
|
+
maxBuilders: resolveMaxBuilders(config)
|
|
364
|
+
},
|
|
365
|
+
plan: {
|
|
366
|
+
sliceGranularity: resolvePlanSliceGranularity(config),
|
|
367
|
+
microTaskPolicy: resolvePlanMicroTaskPolicy(config)
|
|
197
368
|
}
|
|
198
369
|
};
|
|
199
370
|
await writeFileSafe(configPath(projectRoot), stringify(serialisable));
|
|
@@ -196,7 +196,7 @@ export declare const CCLAW_AGENTS: readonly [{
|
|
|
196
196
|
readonly body: string;
|
|
197
197
|
}, {
|
|
198
198
|
readonly name: "slice-builder";
|
|
199
|
-
readonly description: "MANDATORY for
|
|
199
|
+
readonly description: "MANDATORY for delegated TDD slices. Owns RED → GREEN → REFACTOR → per-slice DOC for one feature-atomic implementation unit/slice in a single delegated span. Multiple slice-builder spans run in parallel only under `parallel-builders` topology with disjoint `claimedPaths`; `strict-micro` keeps tiny tasks separate.";
|
|
200
200
|
readonly tools: ["Read", "Write", "Edit", "Grep", "Glob", "Bash"];
|
|
201
201
|
readonly model: "balanced";
|
|
202
202
|
readonly activation: "mandatory";
|
|
@@ -151,7 +151,7 @@ export function sliceBuilderProtocol() {
|
|
|
151
151
|
return [
|
|
152
152
|
"## slice-builder protocol",
|
|
153
153
|
"",
|
|
154
|
-
"**slice-builder** is the canonical worker for **one
|
|
154
|
+
"**slice-builder** is the canonical worker for **one feature-atomic implementation unit/slice** end-to-end: **RED → GREEN → REFACTOR → inline DOC** in **one** delegated span. The unit may contain internal 2-5 minute TDD steps; do not split those into separate agents unless the parent selected `strict-micro`. Multiple slice-builder spans run in parallel only when topology is `parallel-builders` and the wave plan declares disjoint `claimedPaths`.",
|
|
155
155
|
"",
|
|
156
156
|
"### Invariants",
|
|
157
157
|
"- Produce failing RED evidence (or cite the delegated RED artifact) **before** production edits.",
|
|
@@ -165,6 +165,21 @@ export function sliceBuilderProtocol() {
|
|
|
165
165
|
"- Honor every `delegation-record`/`delegation-record.mjs` row shape the controller requests so artifact linters keep passing.",
|
|
166
166
|
"- The umbrella `slice-completed` row ties RED/GREEN/REFACTOR/DOC timestamps to your builder span.",
|
|
167
167
|
"",
|
|
168
|
+
"### Event → status flag table (7.6.0 — phase-event status validation)",
|
|
169
|
+
"",
|
|
170
|
+
"Phase-level granularity is only meaningful on terminal outcomes. The dispatch-level ack (no `--phase`) is the controller saying \"I see the dispatch surface back\" — it stays on `--status=acknowledged`. Phase events MUST use `--status=completed` or `--status=failed`. The hook rejects mismatches with `phase_event_requires_completed_or_failed_status` (exit 2) and prints a corrected-command hint.",
|
|
171
|
+
"",
|
|
172
|
+
"| event | --phase | --status |",
|
|
173
|
+
"|---|---|---|",
|
|
174
|
+
"| dispatch ack (controller-side) | (none) | `acknowledged` |",
|
|
175
|
+
"| RED watched-fail captured | `red` | `completed` |",
|
|
176
|
+
"| GREEN test passes | `green` | `completed` (with `--refactor-outcome=inline\\|deferred\\|...`) |",
|
|
177
|
+
"| REFACTOR landed | `refactor` | `completed` |",
|
|
178
|
+
"| DOC card landed (triggers slice-commit) | `doc` | `completed` |",
|
|
179
|
+
"| BLOCKED / unrecoverable | (any phase reached) | `failed` |",
|
|
180
|
+
"",
|
|
181
|
+
"Common slip: recording every phase event with `--status=acknowledged` (e.g. `--phase=doc --status=acknowledged`). The event row is silently dropped from terminal-phase aggregations, `slice-commit.mjs` never fires (it only triggers on `phase=doc status=completed`), and `wave-status` reports the slice as phantom-open. Recovery requires raw backfill commands. The 7.6.0 hook validator forbids this configuration up front.",
|
|
182
|
+
"",
|
|
168
183
|
"### Streaming output contract",
|
|
169
184
|
"- Emit one JSON line to stdout per completed phase: `{\"event\":\"phase-completed\",\"stage\":\"tdd\",\"sliceId\":\"S-<n>\",\"phase\":\"<red|green|refactor|refactor-deferred|doc>\",\"spanId\":\"<span>\",\"runId\":\"<run>\",\"ts\":\"<iso>\"}`.",
|
|
170
185
|
"- For `phase=green` with inline/deferred refactor folding, include `refactorOutcome.mode` in the same JSON line so live controllers can close the slice without waiting for file sync.",
|
|
@@ -574,7 +589,7 @@ export const CCLAW_AGENTS = [
|
|
|
574
589
|
},
|
|
575
590
|
{
|
|
576
591
|
name: "slice-builder",
|
|
577
|
-
description: "MANDATORY for
|
|
592
|
+
description: "MANDATORY for delegated TDD slices. Owns RED → GREEN → REFACTOR → per-slice DOC for one feature-atomic implementation unit/slice in a single delegated span. Multiple slice-builder spans run in parallel only under `parallel-builders` topology with disjoint `claimedPaths`; `strict-micro` keeps tiny tasks separate.",
|
|
578
593
|
tools: ["Read", "Write", "Edit", "Grep", "Glob", "Bash"],
|
|
579
594
|
model: "balanced",
|
|
580
595
|
activation: "mandatory",
|
package/dist/content/hooks.js
CHANGED
|
@@ -1489,6 +1489,43 @@ async function main() {
|
|
|
1489
1489
|
emitProblems(problems, json, 2);
|
|
1490
1490
|
return;
|
|
1491
1491
|
}
|
|
1492
|
+
// 7.6.0 — phase-event status validation.
|
|
1493
|
+
// \`--phase=<phase>\` carries phase-level granularity (RED/GREEN/REFACTOR/DOC
|
|
1494
|
+
// outcomes). It is only meaningful on terminal statuses
|
|
1495
|
+
// (\`completed\` or \`failed\`). The dispatch-level ack (no phase) keeps
|
|
1496
|
+
// \`--status=acknowledged\`. Refuse acknowledged/launched/scheduled/waived/stale
|
|
1497
|
+
// rows that carry a phase so phantom-open slices cannot be recorded.
|
|
1498
|
+
if (
|
|
1499
|
+
typeof args.phase === "string" &&
|
|
1500
|
+
args.phase.length > 0 &&
|
|
1501
|
+
args.status !== "completed" &&
|
|
1502
|
+
args.status !== "failed"
|
|
1503
|
+
) {
|
|
1504
|
+
const sliceFlag = typeof args.slice === "string" && args.slice.length > 0
|
|
1505
|
+
? "--slice=" + args.slice + " "
|
|
1506
|
+
: "";
|
|
1507
|
+
const spanFlag = typeof args["span-id"] === "string" && args["span-id"].length > 0
|
|
1508
|
+
? "--span-id=" + args["span-id"] + " "
|
|
1509
|
+
: "";
|
|
1510
|
+
const correctedCommandHint =
|
|
1511
|
+
"node .cclaw/hooks/delegation-record.mjs --stage=" + (args.stage || "<stage>") +
|
|
1512
|
+
" --agent=" + (args.agent || "<agent>") +
|
|
1513
|
+
" --mode=" + (args.mode || "mandatory") +
|
|
1514
|
+
" --status=completed --phase=" + args.phase +
|
|
1515
|
+
" " + sliceFlag + spanFlag +
|
|
1516
|
+
'--evidence-ref="<phase outcome>"';
|
|
1517
|
+
emitErrorJson(
|
|
1518
|
+
"phase_event_requires_completed_or_failed_status",
|
|
1519
|
+
{
|
|
1520
|
+
phase: args.phase,
|
|
1521
|
+
status: args.status,
|
|
1522
|
+
spanId: args["span-id"] || "unknown",
|
|
1523
|
+
correctedCommandHint
|
|
1524
|
+
},
|
|
1525
|
+
json
|
|
1526
|
+
);
|
|
1527
|
+
return;
|
|
1528
|
+
}
|
|
1492
1529
|
if (args.phase === "refactor-deferred") {
|
|
1493
1530
|
const rationaleQuality = validateDeferredRationaleInline(args["refactor-rationale"], args);
|
|
1494
1531
|
if (rationaleQuality !== "ok") {
|
|
@@ -57,14 +57,14 @@ If you think any of these, stop and follow the routing flow:
|
|
|
57
57
|
- "I can answer from memory without loading the active stage skill." -> No. Load the skill first.
|
|
58
58
|
- "Hook guard warned, but I can ignore it." -> No. Resolve the warning before continuing.
|
|
59
59
|
- "I'll edit \`.cclaw/state\` directly to move faster." -> No. Use managed commands only.
|
|
60
|
-
- "I'll just do the worker's job inline so we move faster." ->
|
|
60
|
+
- "I'll just do the worker's job inline so we move faster." -> Only if the active TDD topology is explicitly \`inline\`; otherwise see the Controller dispatch discipline below.
|
|
61
61
|
|
|
62
62
|
## Controller dispatch discipline (applies to every stage)
|
|
63
63
|
|
|
64
|
-
cclaw stages have **mandatory delegations** (TDD
|
|
64
|
+
cclaw stages have **mandatory delegations** (TDD normally routes through \`slice-builder\`; review: \`reviewer\` + \`security-reviewer\`; design: \`architect\`; scope: \`planner\`; etc.). The controller is the **orchestrator**, not the worker, except when TDD topology is explicitly \`inline\` for a low-risk unit. When a stage declares a mandatory delegation:
|
|
65
65
|
|
|
66
|
-
- **Dispatch via the harness Task tool.** Do NOT write the worker's output (slice code, review findings, architect notes) into the artifact yourself as a substitute for delegating.
|
|
67
|
-
- **Parallel
|
|
66
|
+
- **Dispatch via the harness Task tool unless topology says inline.** Do NOT write the worker's output (slice code, review findings, architect notes) into the artifact yourself as a substitute for delegating. For TDD \`inline\`, record the routing reason and satisfy the same RED/GREEN/REFACTOR, AC traceability, path containment, managed commit/worktree, lockfile twin, and orphan-change gates.
|
|
67
|
+
- **Parallel only when topology says parallel-builders.** TDD fan-out requires genuinely independent substantial units with disjoint \`claimedPaths\`; review-army (independent reviewer lenses) MUST emit all parallel \`Task\` calls in a SINGLE controller message — not sequentially over multiple turns. The controller waits for all spans to return before reconciling.
|
|
68
68
|
- **Record lifecycle on the same span** via \`delegation-record --status=scheduled|launched|acknowledged|completed\`; the worker emits its own \`--phase=…\` and evidence rows. A \`completed\` row without a matching ACK or dispatch surface is a forgery.
|
|
69
69
|
- **Auto-advance when stage-complete returns ok.** When the helper reports a new \`currentStage\`, immediately load the next stage skill and continue. Announce \`Stage <prev> complete → entering <next>. Continuing.\` Do NOT pause for the user to retype \`/cc\` or say \"продолжай\" — that pause is the failure mode 7.0.2 explicitly removed. The only legitimate stop is a real blocker (missing user input, ambiguous decision, hook fail).
|
|
70
70
|
|
package/dist/content/skills.js
CHANGED
|
@@ -183,22 +183,24 @@ export function tddTopOfSkillBlock(stage) {
|
|
|
183
183
|
return "";
|
|
184
184
|
return `## TDD orchestration primer
|
|
185
185
|
|
|
186
|
-
**MANDATE — controller
|
|
186
|
+
**MANDATE — controller preserves TDD evidence.** In TDD the controller routes, dispatches when needed, and reconciles. Default topology is \`auto\` + \`balanced\`: feature-atomic units contain internal 2-5 minute RED/GREEN/REFACTOR steps. Inline execution is allowed only when \`wave-status\`/the plan selects \`inline\`; it still must satisfy RED-before-GREEN, AC traceability, path containment, verification, managed commit/worktree, lockfile twin, and orphan-change gates. \`single-builder\` and \`parallel-builders\` use \`slice-builder\`; \`strict-micro\` preserves one tiny task per schedulable slice for high-risk work.
|
|
187
187
|
|
|
188
188
|
**Step 1 — Wave status (always first):**
|
|
189
189
|
\`node .cclaw/cli.mjs internal wave-status --json\`
|
|
190
190
|
|
|
191
|
-
The output names: \`waves[]\` (closed/open), \`nextDispatch.waveId\`, \`nextDispatch.mode\` (\`wave-fanout\`, \`single-slice\`, or \`blocked\`), \`nextDispatch.readyToDispatch\` (slice ids), and \`nextDispatch.pathConflicts\` (overlapping \`claimedPaths\` between members).
|
|
191
|
+
The output names: \`waves[]\` (closed/open), \`nextDispatch.waveId\`, \`nextDispatch.mode\` (\`wave-fanout\`, \`single-slice\`, or \`blocked\`), \`nextDispatch.topology\` (\`inline\`, \`single-builder\`, \`parallel-builders\`, or \`strict-micro\`), \`nextDispatch.readyToDispatch\` (slice ids), and \`nextDispatch.pathConflicts\` (overlapping \`claimedPaths\` between members).
|
|
192
192
|
|
|
193
193
|
**Step 2 — Decide automatically (no user question when paths disjoint):**
|
|
194
194
|
|
|
195
|
-
| \`
|
|
196
|
-
|
|
197
|
-
| \`
|
|
198
|
-
| \`
|
|
199
|
-
| \`
|
|
195
|
+
| \`topology\` | \`pathConflicts\` | Action |
|
|
196
|
+
|---------------------------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------|
|
|
197
|
+
| \`parallel-builders\` | \`[]\` | **Fan out independent substantial units in one tool batch.** Emit one \`Task\` per routed ready builder in a single controller message. Do NOT ask. |
|
|
198
|
+
| \`single-builder\` | any/none | Dispatch one \`slice-builder\` for the next feature-atomic unit; serialize remaining ready units. |
|
|
199
|
+
| \`inline\` | \`[]\` | Execute inline only for low-risk inline-safe units; record equivalent RED/GREEN/REFACTOR evidence before completion. |
|
|
200
|
+
| \`strict-micro\` | any/none | Preserve micro-slice sequencing: one tiny task/slice at a time unless the strict plan explicitly proves safe fan-out. |
|
|
201
|
+
| \`blocked\`/mode blocked | non-empty | Issue exactly one AskQuestion (resolve overlap, split/serialize, or adjust claimedPaths), then re-run \`wave-status\`. |
|
|
200
202
|
|
|
201
|
-
**Step 3 — Dispatch protocol per slice:** in the SAME controller message that issues the \`Task\` call:
|
|
203
|
+
**Step 3 — Dispatch protocol per delegated slice:** for \`single-builder\`, \`parallel-builders\`, and delegated \`strict-micro\`, in the SAME controller message that issues the \`Task\` call:
|
|
202
204
|
|
|
203
205
|
1. Append \`delegation-record --status=scheduled\` for the \`slice-builder\` span (one row per slice; reuse the same \`spanId\` across the entire RED → GREEN → REFACTOR → DOC lifecycle).
|
|
204
206
|
2. Append \`delegation-record --status=launched\` immediately after.
|
|
@@ -206,6 +208,8 @@ The output names: \`waves[]\` (closed/open), \`nextDispatch.waveId\`, \`nextDisp
|
|
|
206
208
|
4. The slice-builder span ACKs locally (\`delegation-record --status=acknowledged\`) and runs the **complete** RED → GREEN → REFACTOR → DOC cycle inside the span — including writing \`tdd-slices/S-<id>.md\` and emitting \`--phase=red\`, \`--phase=green\`, \`--phase=refactor\` (or \`--phase=refactor-deferred\` with rationale), and \`--phase=doc\` rows on its own.
|
|
207
209
|
5. The controller waits for ALL parallel spans to terminate before reconciling. Do not page back into the controller chat between spans.
|
|
208
210
|
|
|
211
|
+
For \`inline\`, skip the Task call but do not skip evidence: write the same per-slice card/evidence refs, run RED before GREEN, verify before completion, and keep all path/commit/worktree gates satisfied.
|
|
212
|
+
|
|
209
213
|
**Step 4 — Wave closeout:** after all in-flight slices report \`completed\`:
|
|
210
214
|
|
|
211
215
|
1. Re-run \`wave-status --json\`. Confirm the wave is \`closed\` and the next dispatch is the following wave (or \`closeout\`).
|
|
@@ -272,6 +272,7 @@ const REQUIRED_GATE_IDS = {
|
|
|
272
272
|
"plan_execution_posture_recorded",
|
|
273
273
|
"plan_parallel_exec_full_coverage",
|
|
274
274
|
"plan_wave_paths_disjoint",
|
|
275
|
+
"plan_module_introducing_slice_wires_root",
|
|
275
276
|
"plan_wait_for_confirm"
|
|
276
277
|
],
|
|
277
278
|
tdd: (track) => [
|
|
@@ -677,8 +678,8 @@ const STAGE_AUTO_SUBAGENT_DISPATCH = {
|
|
|
677
678
|
agent: "slice-builder",
|
|
678
679
|
mode: "mandatory",
|
|
679
680
|
requiredAtTier: "lightweight",
|
|
680
|
-
when: "
|
|
681
|
-
purpose: "Own one
|
|
681
|
+
when: "During delegated TDD topologies (`single-builder`, `parallel-builders`, `strict-micro`). Inline topology may skip the dispatch only when the same RED/GREEN/REFACTOR evidence gates are preserved.",
|
|
682
|
+
purpose: "Own one feature-atomic implementation unit/slice end-to-end: RED → GREEN → REFACTOR → per-slice DOC in a single delegated span. Multiple slice-builder spans run in parallel only under `parallel-builders` topology with disjoint `claimedPaths`. Linter rules `tdd_slice_builder_missing` and `tdd_slice_doc_missing` block unauthorized GREEN authors and missing per-slice prose unless inline topology is explicitly recorded.",
|
|
682
683
|
requiresUserGate: false,
|
|
683
684
|
skill: "tdd-cycle-evidence"
|
|
684
685
|
},
|
|
@@ -10,8 +10,8 @@ export const PLAN = {
|
|
|
10
10
|
skillDescription: "Execution planning stage with strict confirmation gate before implementation.",
|
|
11
11
|
philosophy: {
|
|
12
12
|
hardGate: "Do NOT write code or tests. Planning only. This stage produces a task graph and execution order. WAIT_FOR_CONFIRM before any handoff to implementation.",
|
|
13
|
-
ironLaw: "EVERY
|
|
14
|
-
purpose: "Create
|
|
13
|
+
ironLaw: "EVERY IMPLEMENTATION UNIT IS FEATURE-ATOMIC, WITH INTERNAL 2–5 MINUTE TDD STEPS — STRICT MICRO-SLICES ARE RESERVED FOR HIGH-RISK WORK.",
|
|
14
|
+
purpose: "Create feature-atomic implementation units with dependencies, internal TDD steps, and explicit confirmation before execution.",
|
|
15
15
|
whenToUse: [
|
|
16
16
|
"After spec approval",
|
|
17
17
|
"Before writing tests or implementation",
|
|
@@ -43,21 +43,21 @@ export const PLAN = {
|
|
|
43
43
|
"Read upstream — load spec, design, and scope artifacts. Cross-reference acceptance criteria.",
|
|
44
44
|
"Build dependency graph — identify task ordering, parallel opportunities, and blocking dependencies.",
|
|
45
45
|
"Group tasks into dependency batches — batch N+1 cannot start until batch N has verification evidence.",
|
|
46
|
-
"Slice into
|
|
47
|
-
"Task Contract — every
|
|
46
|
+
"Slice into implementation units — each unit is feature-atomic and testable end-to-end, with internal 2-5 minute RED/GREEN/REFACTOR steps. Use `strict-micro` only for high-risk or explicitly requested micro-slice execution.",
|
|
47
|
+
"Task Contract — every unit has one coherent outcome, AC mapping, exact verification command/manual step, and expected evidence snippet or pass condition. Internal steps may be `T-NNN` rows, but they are not automatically separate schedulable agents in balanced/fast mode.",
|
|
48
48
|
"Annotate slice-review metadata — task rows may carry `touchCount` (rough number of files expected to change), `touchPaths` (glob hints, e.g. `migrations/**`, `src/auth/**`), and optional `highRisk: true` to force a review pass. These fields feed the TDD stage's Per-Slice Review point.",
|
|
49
49
|
"For every `### Implementation Unit U-<n>`, declare parallel metadata bullets: `id`, `dependsOn` (unit ids or `none`), `claimedPaths` (repo-relative), `parallelizable` (true|false), `riskTier` (low|standard|high), optional `lane` — used for conflict-aware wave plans and schedulers.",
|
|
50
50
|
"Map scope Locked Decisions — every D-XX ID from scope is referenced by at least one plan task (or explicitly marked deferred with reason).",
|
|
51
51
|
"Run anti-placeholder + anti-scope-reduction scans — block `TODO/TBD/...` and phrasing like `v1`, `for now`, `later` for locked boundaries.",
|
|
52
52
|
"Define validation points — mark where progress must be checked before continuing, with concrete command and expected evidence.",
|
|
53
|
-
"Define execution
|
|
54
|
-
"**Author the FULL Parallel Execution Plan.** Inside the `<!-- parallel-exec-managed-start -->` block, enumerate
|
|
55
|
-
"After authoring/refreshing the managed parallel-exec block, render a Mermaid `flowchart` or `gantt` covering waves (`W-*`) and slice dependencies (`S-*`) so
|
|
53
|
+
"Define execution topology — record `execution.topology` (`auto|inline|single-builder|parallel-builders|strict-micro`), `execution.strictness` (`fast|balanced|strict`), `execution.maxBuilders`, `plan.sliceGranularity`, `plan.microTaskPolicy`, stop conditions, and RED/GREEN/REFACTOR checkpoint/commit expectations. Default posture is `auto` + `balanced`: choose the cheapest safe route, not the most parallel one.",
|
|
54
|
+
"**Author the FULL Parallel Execution Plan.** Inside the `<!-- parallel-exec-managed-start -->` block, enumerate all waves W-01..W-N covering every feature-atomic `U-*` implementation unit/slice. Legacy strict-micro plans may cover each non-deferred `T-NNN` task instead. Each row carries `unit|sliceId | dependsOn | claimedPaths | parallelizable | riskTier | lane`. Do not leave `we'll author waves later`, `next batch only`, or open-ended Backlog handwaves. This fulfills the `plan_parallel_exec_full_coverage` gate. The TDD stage downstream is a pure consumer of these waves — if the plan does not author them, TDD cannot fan out that work.",
|
|
55
|
+
"After authoring/refreshing the managed parallel-exec block, render a Mermaid `flowchart` or `gantt` covering waves (`W-*`) and unit/slice dependencies (`U-*`/`S-*`) so topology and fan-in boundaries are visually auditable.",
|
|
56
56
|
"WAIT_FOR_CONFIRM — write plan artifact and explicitly pause. **STOP.** Do NOT proceed until user confirms. Then close the stage with `node .cclaw/hooks/stage-complete.mjs plan` and tell user to run `/cc`."
|
|
57
57
|
],
|
|
58
58
|
interactionProtocol: [
|
|
59
59
|
"Plan in read-only mode relative to implementation.",
|
|
60
|
-
"Split work into
|
|
60
|
+
"Split work into feature-atomic vertical units; place 2-5 minute TDD steps inside each unit.",
|
|
61
61
|
"Publish explicit dependency batches with entry and exit checks for each batch.",
|
|
62
62
|
"Expose execution posture: sequential vs batch/parallel, stop conditions, and checkpoint cadence for the TDD handoff.",
|
|
63
63
|
"Keep same-wave `claimedPaths` disjoint; if overlap exists, split waves or serialize explicitly before handoff.",
|
|
@@ -79,17 +79,18 @@ export const PLAN = {
|
|
|
79
79
|
"Write plan artifact and pause at WAIT_FOR_CONFIRM."
|
|
80
80
|
],
|
|
81
81
|
requiredGates: [
|
|
82
|
-
{ id: "plan_tasks_sliced_2_5_min", description: "
|
|
82
|
+
{ id: "plan_tasks_sliced_2_5_min", description: "Implementation units are feature-atomic and contain internal 2-5 minute TDD steps; strict micro-slices are explicit." },
|
|
83
83
|
{ id: "plan_dependency_batches_defined", description: "Tasks are grouped into executable batches with gate checks and execution posture." },
|
|
84
84
|
{ id: "plan_acceptance_mapped", description: "Each task maps to a spec acceptance criterion." },
|
|
85
|
-
{ id: "plan_execution_posture_recorded", description: "Execution posture is recorded before implementation handoff." },
|
|
86
|
-
{ id: "plan_parallel_exec_full_coverage", description: "Every T-NNN task in
|
|
85
|
+
{ id: "plan_execution_posture_recorded", description: "Execution topology/posture is recorded before implementation handoff." },
|
|
86
|
+
{ id: "plan_parallel_exec_full_coverage", description: "Every U-* implementation unit/slice (or every T-NNN task in explicit strict-micro plans) is assigned inside the `<!-- parallel-exec-managed-start -->` block; TDD cannot fan out work that the plan never authored as waves." },
|
|
87
87
|
{ id: "plan_wave_paths_disjoint", description: "Within each authored wave, slice `claimedPaths` remain disjoint so `wave-fanout` can dispatch safely without overlap conflicts." },
|
|
88
|
+
{ id: "plan_module_introducing_slice_wires_root", description: "When a slice introduces a new module file, the stack-adapter's wiring aggregator (Rust `lib.rs`, Python `__init__.py`, Node-TS barrel when present) must appear in the same slice's claim or a transitive predecessor's claim so RED can be expressed." },
|
|
88
89
|
{ id: "plan_wait_for_confirm", description: "Execution blocked until explicit user confirmation." }
|
|
89
90
|
],
|
|
90
91
|
requiredEvidence: [
|
|
91
92
|
"Artifact written to `.cclaw/artifacts/05-plan.md`.",
|
|
92
|
-
"
|
|
93
|
+
"Implementation units include acceptance mapping, internal 2-5 minute TDD steps, exact verification command/manual step, and expected evidence/pass condition.",
|
|
93
94
|
"Locked decision coverage table present with D-XX trace links.",
|
|
94
95
|
"Dependency graph documented.",
|
|
95
96
|
"Dependency batches documented with batch-by-batch verification gates.",
|
|
@@ -135,13 +136,13 @@ export const PLAN = {
|
|
|
135
136
|
{ section: "Upstream Handoff", required: false, validationRule: "Summarizes spec/design/scope decisions, constraints, open questions, and explicit drift before task breakdown." },
|
|
136
137
|
{ section: "Dependency Graph", required: false, validationRule: "Ordering and parallel opportunities explicit. No circular dependencies." },
|
|
137
138
|
{ section: "Dependency Batches", required: true, validationRule: "Every task belongs to a batch. Each batch has an exit gate and dependency statement." },
|
|
138
|
-
{ section: "Task List", required: true, validationRule: "
|
|
139
|
+
{ section: "Task List", required: true, validationRule: "Task rows may describe internal 2-5 minute TDD steps. In balanced/fast mode, the schedulable unit is the feature-atomic Implementation Unit, not every T-NNN row. Strict-micro plans may still use one T-NNN per slice." },
|
|
139
140
|
{ section: "Acceptance Mapping", required: true, validationRule: "Every spec criterion is covered by at least one task." },
|
|
140
|
-
{ section: "Execution Posture", required: true, validationRule: "States
|
|
141
|
+
{ section: "Execution Posture", required: true, validationRule: "States `execution.topology` (`auto|inline|single-builder|parallel-builders|strict-micro`), `execution.strictness`, `execution.maxBuilders`, `plan.sliceGranularity`, `plan.microTaskPolicy`, stop conditions, risk triggers, and RED/GREEN/REFACTOR checkpoint or commit expectations for TDD when consistent with the repo workflow." },
|
|
141
142
|
{ section: "Locked Decision Coverage", required: false, validationRule: "Every locked decision ID (D-XX) from scope is listed with linked task IDs or explicit defer rationale." },
|
|
142
143
|
{ section: "Risk Assessment", required: false, validationRule: "If present: per-task or per-batch risk identification with likelihood, impact, and mitigation strategy." },
|
|
143
144
|
{ section: "Boundary Map", required: false, validationRule: "If present: per-batch or per-task interface contracts listing what each task produces (exports) and consumes (imports) from other tasks." },
|
|
144
|
-
{ section: "Implementation Units", required: false, validationRule: "
|
|
145
|
+
{ section: "Implementation Units", required: false, validationRule: "Each `### Implementation Unit U-<n>` includes Goal, Files, Approach, Test scenarios, Verification, internal 2-5 minute TDD steps, plus bullets (`id`, `dependsOn`, `claimedPaths`, `parallelizable`, `riskTier`, optional `lane`)." },
|
|
145
146
|
{ section: "Calibrated Findings", required: false, validationRule: "If present: either `None this stage` or one or more lines in `[P1|P2|P3] (confidence: <n>/10) <path>[:<line>] — <description>` format." },
|
|
146
147
|
{ section: "Regression Iron Rule", required: false, validationRule: "If present: includes `Iron rule acknowledged: yes`." },
|
|
147
148
|
{ section: "WAIT_FOR_CONFIRM", required: true, validationRule: "Explicit marker present. Status: pending until user approves." },
|
|
@@ -155,7 +156,7 @@ export const PLAN = {
|
|
|
155
156
|
title: "Task Decomposition Audit",
|
|
156
157
|
evaluationPoints: [
|
|
157
158
|
"Does every task target a single coherent area (vertical slice)?",
|
|
158
|
-
"
|
|
159
|
+
"Is each implementation unit feature-atomic, with internal steps that fit 2-5 minutes each?",
|
|
159
160
|
"Does every task have an acceptance criterion link, exact verification command/manual step, and expected evidence/pass condition?",
|
|
160
161
|
"Are there tasks that touch multiple unrelated areas?",
|
|
161
162
|
"Would a new engineer understand and start each task within two minutes?"
|
|
@@ -177,7 +178,7 @@ export const PLAN = {
|
|
|
177
178
|
{
|
|
178
179
|
title: "Five-Minute Budget + No-Placeholders Audit",
|
|
179
180
|
evaluationPoints: [
|
|
180
|
-
"Does every
|
|
181
|
+
"Does every internal TDD step carry a bounded 2-to-5-minute estimate or checkbox-level step? Whole units may be larger when feature-atomic.",
|
|
181
182
|
"Are all file paths, test commands, verification commands, and expected evidence copy-pasteable/specific as written — no `TODO`, `TBD`, `FIXME`, `<fill-in>`, `<your-*-here>`, `xxx`, bare `run tests`, or ellipsis standing in for omitted args?",
|
|
182
183
|
"Does every acceptance-criterion reference resolve to a real R# / AC-### in the spec (not a blank link)?",
|
|
183
184
|
"If an estimate is genuinely uncertain (first-time integration, unfamiliar library), is the uncertainty named explicitly and scheduled as a spike task in batch 0, rather than hidden behind a large estimate?"
|