cclaw-cli 0.51.8 → 0.51.10
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/dist/artifact-linter.js +142 -7
- package/dist/content/examples.js +3 -1
- package/dist/content/stages/brainstorm.js +19 -8
- package/dist/content/stages/scope.js +14 -13
- package/dist/content/start-command.js +3 -2
- package/dist/content/templates.js +43 -8
- package/dist/internal/advance-stage.js +25 -2
- package/package.json +1 -1
package/dist/artifact-linter.js
CHANGED
|
@@ -252,7 +252,7 @@ function meaningfulLineCount(sectionBody) {
|
|
|
252
252
|
.filter((line) => line.length > 0)
|
|
253
253
|
.filter((line) => !line.startsWith("<!--"))
|
|
254
254
|
.filter((line) => !/^[-:| ]+$/u.test(line))
|
|
255
|
-
.filter((line) => /[
|
|
255
|
+
.filter((line) => /[\p{L}\p{N}]/u.test(line))
|
|
256
256
|
.length;
|
|
257
257
|
}
|
|
258
258
|
function lineHasToken(line, token) {
|
|
@@ -304,17 +304,21 @@ function tokensFromRule(rule) {
|
|
|
304
304
|
return [];
|
|
305
305
|
}
|
|
306
306
|
/**
|
|
307
|
-
* Extract required keywords from validation rules that contain
|
|
308
|
-
*
|
|
309
|
-
*
|
|
307
|
+
* Extract required keywords from validation rules that contain *backticked*
|
|
308
|
+
* stable tokens after a colon. We only fire on machine-surface enumerations
|
|
309
|
+
* (e.g., `` Must contain: `Status:`, `WAIT_FOR_CONFIRM`, `Approved:` ``);
|
|
310
|
+
* descriptive English prose with bare comma lists is intentionally ignored so
|
|
311
|
+
* authors can write rationale freely without triggering hardcoded keyword
|
|
312
|
+
* matches. Sections that need richer structural enforcement use a dedicated
|
|
313
|
+
* `validateSectionBody` dispatch (see `validateScopeSummary`, etc.).
|
|
310
314
|
*/
|
|
311
315
|
function extractRequiredKeywords(rule) {
|
|
312
316
|
const colonMatch = /:\s*(.+)$/u.exec(rule);
|
|
313
317
|
if (!colonMatch)
|
|
314
318
|
return [];
|
|
315
319
|
const tail = colonMatch[1];
|
|
316
|
-
const
|
|
317
|
-
const phrases =
|
|
320
|
+
const backtickedTokens = Array.from(tail.matchAll(/`([^`]+)`/gu)).map((m) => m[1].trim());
|
|
321
|
+
const phrases = backtickedTokens.filter((p) => p.length >= 2);
|
|
318
322
|
if (phrases.length < 3)
|
|
319
323
|
return [];
|
|
320
324
|
return phrases;
|
|
@@ -366,11 +370,16 @@ function getMarkdownTableRows(sectionBody) {
|
|
|
366
370
|
}
|
|
367
371
|
function getApproachRows(sectionBody) {
|
|
368
372
|
const tableRows = getMarkdownTableRows(sectionBody).map((row) => row.join(" "));
|
|
373
|
+
const headingRows = sectionBody
|
|
374
|
+
.split(/\r?\n/u)
|
|
375
|
+
.map((line) => line.trim())
|
|
376
|
+
.filter((line) => /^#{3,6}\s+\S/u.test(line))
|
|
377
|
+
.map((line) => line.replace(/^#{3,6}\s+/u, ""));
|
|
369
378
|
const bulletRows = sectionBody
|
|
370
379
|
.split(/\r?\n/u)
|
|
371
380
|
.map((line) => line.trim())
|
|
372
381
|
.filter((line) => /^(?:[-*]|\d+\.)\s+\S/u.test(line));
|
|
373
|
-
return [...tableRows, ...bulletRows];
|
|
382
|
+
return [...tableRows, ...headingRows, ...bulletRows];
|
|
374
383
|
}
|
|
375
384
|
function hasSemanticChallenger(row) {
|
|
376
385
|
const normalized = row
|
|
@@ -487,6 +496,126 @@ function validateFailureModeTable(sectionBody) {
|
|
|
487
496
|
details: "Failure Mode Table header and critical-risk checks passed."
|
|
488
497
|
};
|
|
489
498
|
}
|
|
499
|
+
// Canonical scope mode tokens (gstack CEO review). The four mode names live in
|
|
500
|
+
// the scope skill, the artifact template, and downstream traces. Requiring one
|
|
501
|
+
// of them in Scope Summary is **structural** — not free-form English keyword
|
|
502
|
+
// matching on user prose. Authors may also use the canonical short form on a
|
|
503
|
+
// `Mode:` / `Selected mode:` line (e.g. `Selected mode: hold`) as a courtesy.
|
|
504
|
+
const SCOPE_MODE_FULL_TOKENS = [
|
|
505
|
+
"SCOPE EXPANSION",
|
|
506
|
+
"SELECTIVE EXPANSION",
|
|
507
|
+
"HOLD SCOPE",
|
|
508
|
+
"SCOPE REDUCTION"
|
|
509
|
+
];
|
|
510
|
+
const SCOPE_MODE_FULL_REGEX = new RegExp("\\b(?:" +
|
|
511
|
+
SCOPE_MODE_FULL_TOKENS
|
|
512
|
+
.map((token) => token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\s+/g, "[\\s_-]+"))
|
|
513
|
+
.join("|") +
|
|
514
|
+
")\\b", "iu");
|
|
515
|
+
// Short-form synonyms accepted only when stamped on an explicit `Mode:` /
|
|
516
|
+
// `Selected mode:` / `Scope mode:` line. Plain prose with the same word does
|
|
517
|
+
// not count, so `strict` / `broad` / `narrow` / similar non-mode adjectives
|
|
518
|
+
// remain rejected.
|
|
519
|
+
const SCOPE_MODE_LINE_REGEX = /(?:^|\n)\s*[-*]?\s*\**\s*(?:Selected\s+|Scope\s+)?Mode\**\s*:\s*\**\s*([^\n]+)/iu;
|
|
520
|
+
const SCOPE_MODE_SHORT_TOKEN_REGEX = /\b(?:hold(?:[\s_-]?scope)?|selective(?:[\s_-]?expansion)?|scope[\s_-]?expansion|expansion|scope[\s_-]?reduction|reduction|expand|reduce)\b/iu;
|
|
521
|
+
// Next-stage handoff token. We only enforce the canonical machine-surface stage
|
|
522
|
+
// IDs (`design`, `spec`) plus stable handoff phrases. The surrounding prose may
|
|
523
|
+
// be written in any language — this guards the downstream cross-stage trace,
|
|
524
|
+
// not the wording of the rationale.
|
|
525
|
+
const NEXT_STAGE_HANDOFF_REGEX = /(?:`(?:design|spec)`|\bdesign\b|\bspec\b|next[-\s_]stage|next stage|handoff|hand[-\s]off)/iu;
|
|
526
|
+
function hasCanonicalScopeMode(body) {
|
|
527
|
+
if (SCOPE_MODE_FULL_REGEX.test(body))
|
|
528
|
+
return true;
|
|
529
|
+
for (const match of body.matchAll(new RegExp(SCOPE_MODE_LINE_REGEX, "giu"))) {
|
|
530
|
+
const value = match[1] ?? "";
|
|
531
|
+
if (SCOPE_MODE_SHORT_TOKEN_REGEX.test(value))
|
|
532
|
+
return true;
|
|
533
|
+
}
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
function validatePremiseChallenge(sectionBody) {
|
|
537
|
+
// gstack-style premise challenge requires a real Q/A structure (table or
|
|
538
|
+
// list), not free-form prose. The validation is *structural* only — we do
|
|
539
|
+
// NOT keyword-grep for English phrases like "right problem"; authors may
|
|
540
|
+
// write the questions in any language, and the answers carry the meaning.
|
|
541
|
+
// The template ships with canonical question labels as scaffolding, but
|
|
542
|
+
// the linter only enforces that the section actually compares premise
|
|
543
|
+
// questions to answers.
|
|
544
|
+
const tableRows = getMarkdownTableRows(sectionBody);
|
|
545
|
+
const bulletRows = sectionBody
|
|
546
|
+
.split(/\r?\n/u)
|
|
547
|
+
.map((line) => line.trim())
|
|
548
|
+
.filter((line) => /^(?:[-*]|\d+\.)\s+\S/u.test(line));
|
|
549
|
+
const rowCount = Math.max(tableRows.length, bulletRows.length);
|
|
550
|
+
if (rowCount < 3) {
|
|
551
|
+
return {
|
|
552
|
+
ok: false,
|
|
553
|
+
details: `Premise Challenge needs at least 3 question/answer rows in a table or bullet list (right problem? / direct path? / what if nothing? are the gstack default trio). Found ${rowCount}.`
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
// For tables, each data row must have at least 2 non-empty cells so the
|
|
557
|
+
// section is genuinely a Q/A comparison, not a list of headlines. For
|
|
558
|
+
// bullet lists, each line must be substantive (>= 8 characters of letters
|
|
559
|
+
// or digits) so we don't accept three-letter placeholders like `- a`.
|
|
560
|
+
if (tableRows.length >= 3) {
|
|
561
|
+
const sparseRows = tableRows.filter((row) => {
|
|
562
|
+
const filledCells = row.filter((cell) => cell.replace(/[\s|]/gu, "").length >= 2);
|
|
563
|
+
return filledCells.length < 2;
|
|
564
|
+
});
|
|
565
|
+
if (sparseRows.length > 0) {
|
|
566
|
+
return {
|
|
567
|
+
ok: false,
|
|
568
|
+
details: "Premise Challenge table rows must populate at least the question and answer columns (no empty answers)."
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
else if (bulletRows.length >= 3) {
|
|
573
|
+
const sparseBullets = bulletRows.filter((line) => {
|
|
574
|
+
const cleaned = line.replace(/^[-*\d.\s]+/u, "").replace(/[`*_]/gu, "").trim();
|
|
575
|
+
const hasQuestionMark = /\?/u.test(cleaned);
|
|
576
|
+
const meaningful = cleaned.match(/[\p{L}\p{N}]/gu)?.length ?? 0;
|
|
577
|
+
return !hasQuestionMark && meaningful < 12;
|
|
578
|
+
});
|
|
579
|
+
if (sparseBullets.length > bulletRows.length - 3) {
|
|
580
|
+
return {
|
|
581
|
+
ok: false,
|
|
582
|
+
details: "Premise Challenge bullet list must include at least 3 substantive Q/A lines (a question mark plus the answer, or a labelled `Question: answer` pair)."
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return {
|
|
587
|
+
ok: true,
|
|
588
|
+
details: `Premise Challenge structures ${rowCount} Q/A rows.`
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
function validateScopeSummary(sectionBody) {
|
|
592
|
+
const meaningfulLines = sectionBody
|
|
593
|
+
.split(/\r?\n/)
|
|
594
|
+
.map((line) => line.trim())
|
|
595
|
+
.filter((line) => line.length > 0 && /[\p{L}\p{N}]/u.test(line));
|
|
596
|
+
if (meaningfulLines.length < 2) {
|
|
597
|
+
return {
|
|
598
|
+
ok: false,
|
|
599
|
+
details: "Scope Summary must list at least 2 substantive lines covering the selected mode and the next-stage handoff."
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
if (!hasCanonicalScopeMode(sectionBody)) {
|
|
603
|
+
return {
|
|
604
|
+
ok: false,
|
|
605
|
+
details: "Scope Summary must name the selected mode using a canonical token (SCOPE EXPANSION, SELECTIVE EXPANSION, HOLD SCOPE, SCOPE REDUCTION) or a short form on a `Mode:` line (hold, selective, expansion, reduction)."
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
if (!NEXT_STAGE_HANDOFF_REGEX.test(sectionBody)) {
|
|
609
|
+
return {
|
|
610
|
+
ok: false,
|
|
611
|
+
details: "Scope Summary must record the track-aware next-stage handoff (mention `design` for standard, `spec` for medium, or include a `Next-stage handoff:` line)."
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
return {
|
|
615
|
+
ok: true,
|
|
616
|
+
details: "Scope Summary names the selected mode and the next-stage handoff."
|
|
617
|
+
};
|
|
618
|
+
}
|
|
490
619
|
const INTERACTION_EDGE_CASE_REQUIREMENTS = [
|
|
491
620
|
{ label: "double-click", pattern: /\bdouble[\s-]?click\b/iu },
|
|
492
621
|
{
|
|
@@ -1207,6 +1336,12 @@ function validateSectionBody(sectionBody, rule, sectionName) {
|
|
|
1207
1336
|
if (sectionNameNormalized === "pre-scope system audit") {
|
|
1208
1337
|
return validatePreScopeSystemAudit(sectionBody);
|
|
1209
1338
|
}
|
|
1339
|
+
if (sectionNameNormalized === "scope summary") {
|
|
1340
|
+
return validateScopeSummary(sectionBody);
|
|
1341
|
+
}
|
|
1342
|
+
if (sectionNameNormalized === "premise challenge") {
|
|
1343
|
+
return validatePremiseChallenge(sectionBody);
|
|
1344
|
+
}
|
|
1210
1345
|
if (sectionNameNormalized === "data flow") {
|
|
1211
1346
|
return validateInteractionEdgeCaseMatrix(sectionBody);
|
|
1212
1347
|
}
|
package/dist/content/examples.js
CHANGED
|
@@ -142,9 +142,11 @@ The original premise (“add notifications”) was reframed to **“ensure users
|
|
|
142
142
|
|
|
143
143
|
## Scope Summary
|
|
144
144
|
|
|
145
|
+
- Selected mode: SELECTIVE EXPANSION (cherry-pick durable feed on hold-scope baseline).
|
|
145
146
|
- Accepted scope: durable feed + SSE + explicit degraded UX.
|
|
146
147
|
- Deferred: WebSocket channel and rich-media/search enhancements.
|
|
147
|
-
- Explicitly excluded: outbound channels and marketing workflows for v1
|
|
148
|
+
- Explicitly excluded: outbound channels and marketing workflows for v1.
|
|
149
|
+
- Next-stage handoff: design — carry the durable-feed contract, SSE failover paths, and degraded-UX expectations into architecture lock-in.`,
|
|
148
150
|
design: `## Codebase Investigation (blast-radius files)
|
|
149
151
|
|
|
150
152
|
| File | Current responsibility | Patterns discovered |
|
|
@@ -36,23 +36,29 @@ export const BRAINSTORM = {
|
|
|
36
36
|
},
|
|
37
37
|
executionModel: {
|
|
38
38
|
checklist: [
|
|
39
|
-
"**Explore project context** — inspect existing files/docs/recent activity before asking what to build.",
|
|
39
|
+
"**Explore project context** — inspect existing files/docs/recent activity before asking what to build; capture matching files/patterns/seeds in `Context > Discovered context` so downstream stages don't redo discovery.",
|
|
40
40
|
"**Classify depth and scope** — pick Lightweight / Standard / Deep; decompose independent subsystems before deeper work.",
|
|
41
|
+
"**Premise check (one pass)** — answer the three gstack-style questions in the artifact body: *Right problem? Direct path? What if we do nothing?* Take a position; do not hedge.",
|
|
42
|
+
"**Reframe with How Might We** — write a single `How Might We …?` line that names the user, the desired outcome, and the constraint. This is the altitude check before approaches.",
|
|
43
|
+
"**Sharpening questions (3-5)** — capture decision-changing question/answer pairs in the `Sharpening Questions` table with the actual decision impact; if a question would not change architecture/scope/UX, state the assumption and skip it.",
|
|
41
44
|
"**Use compact discovery for simple apps** — for concrete low-risk asks (todo app, landing page, local widget), do one context pass, compare one baseline and one challenger, then ask for one explicit approval; do not drag the user through a full workshop.",
|
|
42
45
|
"**Short-circuit concrete asks** — for unambiguous implementation-only requests, write a compact brainstorm stub (context, problem, approved intent, constraints, assumptions) and ask for one explicit approval.",
|
|
43
46
|
"**Ask only decision-changing questions** — one at a time; if answers would not change approach, state the assumption and continue.",
|
|
44
|
-
"**Compare 2-3 distinct approaches** — include real trade-offs
|
|
47
|
+
"**Compare 2-3 distinct approaches with stable Role/Upside columns** — Role values are `baseline` | `challenger` | `wild-card`; Upside is `low` | `modest` | `high` | `higher`; include real trade-offs and reuse notes; include exactly one challenger with explicit `high` or `higher` upside.",
|
|
45
48
|
"**Collect reaction before recommending** — ask which option feels closest and what concern remains, then recommend based on that reaction.",
|
|
46
|
-
"**Write
|
|
49
|
+
"**Write the `Not Doing` list** — name 3-5 things this brainstorm explicitly is not committing to (vs. deferred). This protects scope from silent enlargement and the next stage from rework.",
|
|
50
|
+
"**Self-review before user approval** — re-read the artifact and patch contradictions, weak trade-offs, placeholders, ambiguity, and weak handoff language; record the patch list in `Self-Review Notes` (or `- None.`).",
|
|
47
51
|
"**Request explicit approval** — state exactly what direction is being approved; do not advance without approval and artifact review.",
|
|
48
52
|
"**Handoff** — only after approval, complete the stage and point to `/cc-next`."
|
|
49
53
|
],
|
|
50
54
|
interactionProtocol: [
|
|
51
|
-
"Start from observed project context; if the idea is vague, first narrow the project type.",
|
|
55
|
+
"Start from observed project context; if the idea is vague, first narrow the project type with **one** structured question, then keep going.",
|
|
56
|
+
"Lead with the premise check (right problem / direct path / what if nothing) and the `How Might We` reframing before approaches; both go in the artifact, not just the chat.",
|
|
52
57
|
"Ask at most one question per turn, only when decision-changing; if using a structured question tool, send exactly one question object, not a multi-question form.",
|
|
53
|
-
"If likely answers do not change architecture or scope boundaries, choose the default and state the assumption.",
|
|
54
|
-
"For simple greenfield web apps, present a compact A/B choice with one recommended path and one higher-upside challenger; keep the artifact concise but structurally complete.",
|
|
58
|
+
"If likely answers do not change architecture or scope boundaries, choose the default and state the assumption inline.",
|
|
59
|
+
"For simple greenfield web apps, present a compact A/B choice with one recommended path and one higher-upside challenger; keep the artifact concise but structurally complete (Context, Premise, How Might We, Sharpening Questions, Approaches, Reaction, Selected Direction, Not Doing).",
|
|
55
60
|
"Show approaches before the recommendation; include a higher-upside challenger and gather reaction first.",
|
|
61
|
+
"Self-review before approval: re-read the artifact, fix contradictions/placeholders/weak trade-offs, then ask for approval. Do not ask for approval on a draft you have not re-read.",
|
|
56
62
|
"State exactly what is being approved, then **STOP** until the user explicitly approves the artifact."
|
|
57
63
|
],
|
|
58
64
|
process: [
|
|
@@ -117,16 +123,21 @@ export const BRAINSTORM = {
|
|
|
117
123
|
traceabilityRule: "Scope and design decisions must trace back to explored context and approved brainstorm direction."
|
|
118
124
|
},
|
|
119
125
|
artifactValidation: [
|
|
120
|
-
{ section: "Context", required: true, validationRule: "Must reference project state and relevant existing code or patterns." },
|
|
126
|
+
{ section: "Context", required: true, validationRule: "Must reference project state and relevant existing code or patterns. A `Discovered context` subsection (or list) is recommended for downstream traceability." },
|
|
121
127
|
{ section: "Problem", required: true, validationRule: "Must define what we're solving, success criteria, and constraints." },
|
|
128
|
+
{ section: "Premise Check", required: false, validationRule: "Recommended: explicit answers to `Right problem?`, `Direct path?`, `What if we do nothing?` — take a position, do not hedge." },
|
|
129
|
+
{ section: "How Might We", required: false, validationRule: "Recommended: a single `How Might We …?` line naming the user, the outcome, and the binding constraint." },
|
|
130
|
+
{ section: "Sharpening Questions", required: false, validationRule: "Recommended: 3-5 question/answer pairs with explicit `Decision impact` so downstream stages see what each answer changed." },
|
|
122
131
|
{ section: "Clarifying Questions", required: false, validationRule: "Must capture question, answer, and decision impact for each clarifying question." },
|
|
123
132
|
{ section: "Approach Tier", required: true, validationRule: "Must classify depth as Lightweight/Standard/Deep and explain why." },
|
|
124
133
|
{ section: "Short-Circuit Decision", required: false, validationRule: "Must include Status/Why/Scope handoff lines when short-circuit is discussed; compact stubs are valid for concrete asks." },
|
|
125
|
-
{ section: "Approaches", required: true, validationRule: "Must compare 2-3 distinct options with real trade-offs
|
|
134
|
+
{ section: "Approaches", required: true, validationRule: "Must compare 2-3 distinct options with real trade-offs. Use the canonical `Role` column with `baseline` | `challenger` | `wild-card` and the `Upside` column with `low` | `modest` | `high` | `higher`; include exactly one challenger row with `high` or `higher` upside." },
|
|
126
135
|
{ section: "Approach Reaction", required: true, validationRule: "Must appear before Selected Direction and summarize user reaction before recommendation, including `Closest option`, `Concerns`, and what changed after reaction." },
|
|
127
136
|
{ section: "Selected Direction", required: true, validationRule: "Must include the selected approach, an explicit approval marker, rationale traceable to the prior Approach Reaction, and a track-aware next-stage handoff." },
|
|
137
|
+
{ section: "Not Doing", required: false, validationRule: "Recommended: 3-5 explicitly non-committed items (distinct from deferred). Protects scope from silent enlargement and the next stage from rework." },
|
|
128
138
|
{ section: "Design", required: false, validationRule: "Must cover architecture, key components, and data flow scaled to complexity." },
|
|
129
139
|
{ section: "Visual Companion", required: false, validationRule: "If architecture/data-flow complexity is medium+, include compact ASCII/Mermaid diagram or explicitly justify omission." },
|
|
140
|
+
{ section: "Self-Review Notes", required: false, validationRule: "Recommended: list of patches applied during self-review (or `- None.`) — done before requesting user approval." },
|
|
130
141
|
{ section: "Assumptions and Open Questions", required: false, validationRule: "Must capture unresolved assumptions/open questions, or explicitly state none." }
|
|
131
142
|
],
|
|
132
143
|
trivialOverrideSections: [
|
|
@@ -46,31 +46,32 @@ export const SCOPE = {
|
|
|
46
46
|
executionModel: {
|
|
47
47
|
checklist: [
|
|
48
48
|
"**Compact CEO pass first** — read brainstorm, name the job-to-be-done, challenge whether this is the right product slice, and propose the highest-leverage scope in one pass. For simple apps, keep this to a tight scope contract instead of a full strategy workshop.",
|
|
49
|
-
"**
|
|
49
|
+
"**Premise and leverage check** — answer in the artifact: *Right problem? Direct path? What if nothing? Where can we leverage existing code? What is the reversibility cost?* Take a position; do not hedge.",
|
|
50
50
|
"**Draft the 10-star vs current-slice boundary** — show what would make the product meaningfully better, then explicitly choose what ships now, what is deferred, and what is excluded without using vague `later/for now` placeholders.",
|
|
51
|
-
"**
|
|
52
|
-
"**
|
|
53
|
-
"**
|
|
51
|
+
"**Pick one of four gstack modes with the user** — SCOPE EXPANSION, SELECTIVE EXPANSION, HOLD SCOPE, or SCOPE REDUCTION. Recommend one, state why and what signal would change it, then STOP for the user's mode/scope approval before writing the final artifact.",
|
|
52
|
+
"**Run mode-specific analysis** — match the analysis to the chosen mode: SCOPE EXPANSION enumerates 10x opportunities + delight features; SELECTIVE EXPANSION lists baseline + cherry-picked additions with leverage rationale; HOLD SCOPE proves rigor on the current slice; SCOPE REDUCTION names the smallest useful wedge and what is cut, with follow-up split.",
|
|
53
|
+
"**Compare implementation alternatives** — include minimum viable, product-grade, and ideal architecture options with effort (S/M/L/XL), risk (Low/Med/High), pros, cons, and reuses. Recommend one and tie it to mode.",
|
|
54
|
+
"**Run outside voice before final approval** — for simple/low-risk scope, record one concise adversarial self-check row; for complex/high-risk/configured scope, iterate until threshold. Record the loop summary in `## Spec Review Loop`, but do not treat it as user approval.",
|
|
54
55
|
"**Ask only one decision-changing question** — if the user rejects the contract but is unsure, offer 3-4 concrete scope moves instead of open-ended interrogation.",
|
|
55
|
-
"**Write the scope contract** — include in-scope/out-of-scope, discretion areas, deferred items, locked decisions, error/rescue notes, completion dashboard, scope summary
|
|
56
|
+
"**Write the scope contract after approval** — include in-scope/out-of-scope, discretion areas, deferred items, locked decisions, error/rescue notes, completion dashboard, scope summary (with canonical mode token + next-stage handoff), and explicit approval evidence."
|
|
56
57
|
],
|
|
57
58
|
interactionProtocol: [
|
|
58
59
|
decisionProtocolInstruction("scope mode selection", "present expand/selective/hold/reduce as labeled options with trade-offs and mark one as (recommended)", "recommend the option that best covers the prime-directive failure modes, four data-flow paths, observability, and deferred handling for the in-scope set with the smallest blast radius. Base your recommendation on default heuristics: greenfield -> expand, enhancement -> selective, bugfix/hotfix/refactor -> hold, broad blast radius -> reduce"),
|
|
59
|
-
"Do not walk the full checklist by default. Lead with
|
|
60
|
-
"For simple web-app flows, default to HOLD SCOPE or SELECTIVE EXPANSION, show the exact in/out/deferred contract, and
|
|
60
|
+
"Do not walk the full checklist by default. Lead with a proposed scope contract and the one decision that matters most; label the mode as recommended, not selected, until the user answers.",
|
|
61
|
+
"For simple web-app flows, default to HOLD SCOPE or SELECTIVE EXPANSION, show the exact in/out/deferred contract as a proposal, and STOP for one explicit approval before writing the final scope artifact or completing the stage.",
|
|
61
62
|
"Challenge premise first, take a firm position, and name one concrete condition that would change it.",
|
|
62
63
|
"Push back on weak framing: vague scope needs a specific user/problem, platform vision needs a narrow wedge, social proof needs behavioral evidence.",
|
|
63
64
|
"Resolve one structural scope issue at a time; otherwise state the assumption and move on.",
|
|
64
65
|
"If the user says no but cannot name the change, offer concrete moves: keep scope, add one obvious adjacent capability, reduce to wedge, or re-open stack/product direction.",
|
|
65
66
|
`Before final approval, record outside-voice findings and a \`## Spec Review Loop\` table using ${reviewLoopPolicySummary("scope")}`,
|
|
66
|
-
"**STOP.** Wait for explicit approval of the scope contract before advancing.",
|
|
67
|
-
"**STOP BEFORE ADVANCE.** Mandatory delegation `planner` must be completed or explicitly waived. If no isolated planner is available, use `--waive-delegation=planner --waiver-reason=\"role-switch scope self-review completed\"`. Then close with `node .cclaw/hooks/stage-complete.mjs scope --passed=scope_mode_selected,scope_contract_written,scope_user_approved --evidence-json '{\"scope_mode_selected\":\"<mode + rationale>\",\"scope_contract_written\":\"<artifact path + sections>\"}'`.
|
|
67
|
+
"**STOP.** Wait for explicit user approval of the scope mode and scope contract before writing final approval language or advancing.",
|
|
68
|
+
"**STOP BEFORE ADVANCE.** Mandatory delegation `planner` must be completed or explicitly waived. If no isolated planner is available, use `--waive-delegation=planner --waiver-reason=\"role-switch scope self-review completed\"`. Then close with `node .cclaw/hooks/stage-complete.mjs scope --passed=scope_mode_selected,scope_contract_written,scope_user_approved --evidence-json '{\"scope_mode_selected\":\"<user-approved mode + rationale>\",\"scope_contract_written\":\"<artifact path + sections>\",\"scope_user_approved\":\"<explicit user approval quote or summary>\"}'`. `scope_user_approved` must cite the user's approval; review-loop evidence alone is not approval."
|
|
68
69
|
],
|
|
69
70
|
process: [
|
|
70
71
|
"Run configured pre-scope audit only when enabled.",
|
|
71
72
|
"Run the gstack-style CEO scope pass scaled to risk: job-to-be-done, premise challenge, 10-star upside, smallest useful wedge, and what would change the recommendation.",
|
|
72
73
|
"Compare minimum viable, product-grade, and ideal architecture scope alternatives with explicit reuse/effort/risk.",
|
|
73
|
-
"
|
|
74
|
+
"Recommend a scope mode with explicit rationale, then ask for user opt-in before treating it as selected.",
|
|
74
75
|
"Run outside voice / adversarial self-check before final approval and record a valid `## Spec Review Loop` table.",
|
|
75
76
|
"Write explicit scope contract, discretion areas, deferred items, error/rescue registry, and D-XX locked decisions.",
|
|
76
77
|
"Produce scope summary, completion dashboard, and exact next-stage handoff before asking final approval."
|
|
@@ -89,7 +90,7 @@ export const SCOPE = {
|
|
|
89
90
|
"Locked Decisions section lists stable D-XX IDs for non-negotiable boundaries.",
|
|
90
91
|
"Premise challenge findings documented.",
|
|
91
92
|
"Outside Voice findings and dispositions are recorded (accept/reject/defer with rationale) before final approval.",
|
|
92
|
-
`Spec review loop summary includes a table with columns Iteration, Quality Score, Findings, plus Stop reason, Target score, and Max iterations.
|
|
93
|
+
`Spec review loop summary includes a table with columns Iteration, Quality Score, Findings, plus Stop reason, Target score, and Max iterations. This is outside-voice evidence only; it does not satisfy user approval. ${reviewLoopPolicySummary("scope")}`,
|
|
93
94
|
reviewLoopSecondOpinionSummary("scope"),
|
|
94
95
|
"Deferred items list with one-line rationale for each.",
|
|
95
96
|
"When an upside deferred idea is parked, a seed file is created under `.cclaw/seeds/` and referenced in the artifact.",
|
|
@@ -138,7 +139,7 @@ export const SCOPE = {
|
|
|
138
139
|
{ section: "Upstream Handoff", required: false, validationRule: "Summarizes brainstorm/idea decisions, constraints, open questions, and explicit drift before scope decisions." },
|
|
139
140
|
{ section: "Pre-Scope System Audit", required: false, validationRule: "When `.cclaw/config.yaml::optInAudits.scopePreAudit` is true: must capture git log -30, git diff --stat, git stash list, and debt-marker scan (TODO/FIXME/XXX/HACK) before premise challenge." },
|
|
140
141
|
{ section: "Prime Directives", required: false, validationRule: "For each scoped capability: named failure modes, explicit error surface, four data-flow paths, interaction edge cases, observability expectations, and deferred-item handling." },
|
|
141
|
-
{ section: "Premise Challenge", required: false, validationRule: "Must
|
|
142
|
+
{ section: "Premise Challenge", required: false, validationRule: "Must list at least 3 question/answer rows in a markdown table or bullet list (gstack default trio: right problem? direct path? what if we do nothing? — extend with leverage and reversibility for richer scope). The linter enforces structure, not English wording — answers may be in any language." },
|
|
142
143
|
{ section: "Landscape Check", required: false, validationRule: "When mode is EXPAND/SELECTIVE, include at least one external reference insight and its impact on scope." },
|
|
143
144
|
{ section: "Taste Calibration", required: false, validationRule: "Must reference 2-3 strong in-repo modules/files that define the quality bar or explicitly justify omission." },
|
|
144
145
|
{ section: "Requirements", required: false, validationRule: "Table of stable requirement IDs (R1, R2, R3…) one per row with observable outcome, priority, and source. IDs are assigned once and never renumbered across scope/design/spec/plan/review; dropped requirements stay with Priority `DROPPED`." },
|
|
@@ -153,7 +154,7 @@ export const SCOPE = {
|
|
|
153
154
|
{ section: "Outside Voice Findings", required: false, validationRule: "Must list external/adversarial findings and disposition (accept/reject/defer) with rationale." },
|
|
154
155
|
{ section: "Spec Review Loop", required: false, validationRule: `Must record iterations, quality score per iteration, stop reason, and unresolved concerns. Enforce ${reviewLoopPolicySummary("scope")}` },
|
|
155
156
|
{ section: "Completion Dashboard", required: true, validationRule: "Lists per-review-section status, count of critical/open gaps, resolved decisions, and unresolved decisions (or 'None')." },
|
|
156
|
-
{ section: "Scope Summary", required: true, validationRule: "
|
|
157
|
+
{ section: "Scope Summary", required: true, validationRule: "Compact recap of the locked scope. Must name the selected mode using one of the canonical tokens (`SCOPE EXPANSION`, `SELECTIVE EXPANSION`, `HOLD SCOPE`, `SCOPE REDUCTION`) and record the track-aware next-stage handoff (`design` for standard, `spec` for medium); the linter checks structure, not English wording." },
|
|
157
158
|
{ section: "Dream State Mapping", required: false, validationRule: "If present (complex projects): CURRENT STATE, THIS PLAN, 12-MONTH IDEAL, and alignment verdict." },
|
|
158
159
|
{ section: "Temporal Interrogation", required: false, validationRule: "If present (complex projects): timeline simulation table with decision pressures and lock-now vs defer verdicts." }
|
|
159
160
|
]
|
|
@@ -70,7 +70,7 @@ ${conversationLanguagePolicyMarkdown()}
|
|
|
70
70
|
Skip detection quietly if no markers are found — do NOT invent a stack.
|
|
71
71
|
|
|
72
72
|
5. Read \`${flowPath}\`.
|
|
73
|
-
6. If flow already has completed stages, warn the user that starting a new tracked flow will reset progress. Ask for confirmation before proceeding.
|
|
73
|
+
6. If flow already has completed stages, warn the user that starting a new tracked flow will reset progress. Ask for confirmation before proceeding. A fresh init placeholder state with \`completedStages: []\`, no passed gates, and no \`00-idea.md\` is **not** an active flow; do not ask the user to resume it.
|
|
74
74
|
7. **Track heuristic** — classify the idea text and **recommend** a track (the user can override before any state mutation):
|
|
75
75
|
- First, load \`${RUNTIME_ROOT}/config.yaml\`. If \`trackHeuristics\` is defined, apply those per-track vocabulary hints (\`fallback\`, \`tracks.<id>.{triggers,veto}\`) on top of the built-in defaults. Evaluation order is always \`standard -> medium -> quick\` (narrow-to-broad).
|
|
76
76
|
- **quick** (\`spec → tdd → review → ship\`) — single-purpose work where the spec is essentially already known.
|
|
@@ -152,7 +152,7 @@ description: "Unified entry point for the cclaw flow. No args = resume/next. Wit
|
|
|
152
152
|
|
|
153
153
|
## HARD-GATE
|
|
154
154
|
|
|
155
|
-
Do **not** silently discard an existing flow when the user provides a prompt. If completed stages exist, inform and confirm before resetting.
|
|
155
|
+
Do **not** silently discard an existing flow when the user provides a prompt. If completed stages exist, inform and confirm before resetting. A freshly initialized placeholder state with \`completedStages: []\`, no passed gates, and no \`${RUNTIME_ROOT}/artifacts/00-idea.md\` is not an active flow; classify the prompt and start normally.
|
|
156
156
|
|
|
157
157
|
${conversationLanguagePolicyMarkdown()}
|
|
158
158
|
## Protocol
|
|
@@ -168,6 +168,7 @@ ${conversationLanguagePolicyMarkdown()}
|
|
|
168
168
|
- Inform: "You have an active flow at stage **{currentStage}** with {N} completed stages. Starting a new tracked flow will reset progress."
|
|
169
169
|
- Ask: "Continue with reset? (A) Yes, start fresh (B) No, resume current flow"
|
|
170
170
|
- If (B) → switch to Path B behavior.
|
|
171
|
+
If \`completedStages\` is empty, all gate \`passed\` arrays are empty, and \`${RUNTIME_ROOT}/artifacts/00-idea.md\` is missing, treat it as a fresh init placeholder — do **not** ask whether to continue the current flow.
|
|
171
172
|
7. **Classify the idea** using the heuristic below and present one compact Start framing summary (class, track, stack, origin docs, seed recalls, next action). Wait for explicit confirmation or override before mutating any state only when reset/conflict/ambiguity makes it necessary.
|
|
172
173
|
- If \`${RUNTIME_ROOT}/config.yaml\` defines \`trackHeuristics\`, apply those vocabulary hints (\`fallback\`, \`tracks.<id>.{triggers,veto}\`) on top of built-in defaults. Evaluation order is fixed: \`standard -> medium -> quick\`. (Honest note: this is advisory prose; the LLM applies it, not a Node-level router.)
|
|
173
174
|
|
|
@@ -26,11 +26,29 @@ export const ARTIFACT_TEMPLATES = {
|
|
|
26
26
|
- **Project state:**
|
|
27
27
|
- **Relevant existing code/patterns:**
|
|
28
28
|
|
|
29
|
+
### Discovered context
|
|
30
|
+
- (paths, prior artifacts, seeds, prompt fragments — referenced by downstream stages, or \`- None.\`)
|
|
31
|
+
|
|
29
32
|
## Problem
|
|
30
33
|
- **What we're solving:**
|
|
31
34
|
- **Success criteria:**
|
|
32
35
|
- **Constraints:**
|
|
33
36
|
|
|
37
|
+
## Premise Check
|
|
38
|
+
- **Right problem?** (yes/no + one-line justification — take a position)
|
|
39
|
+
- **Direct path?** (yes/no + one-line justification)
|
|
40
|
+
- **What if we do nothing?** (concrete consequence, not "nothing happens")
|
|
41
|
+
|
|
42
|
+
## How Might We
|
|
43
|
+
- *How might we …?* — one line naming the user, the desired outcome, and the binding constraint.
|
|
44
|
+
|
|
45
|
+
## Sharpening Questions
|
|
46
|
+
| # | Question | Answer / Assumption | Decision impact |
|
|
47
|
+
|---|---|---|---|
|
|
48
|
+
| 1 | | | |
|
|
49
|
+
| 2 | | | |
|
|
50
|
+
| 3 | | | |
|
|
51
|
+
|
|
34
52
|
## Clarifying Questions
|
|
35
53
|
| # | Question | Answer | Decision impact |
|
|
36
54
|
|---|---|---|---|
|
|
@@ -46,10 +64,12 @@ export const ARTIFACT_TEMPLATES = {
|
|
|
46
64
|
- Scope handoff:
|
|
47
65
|
|
|
48
66
|
## Approaches
|
|
49
|
-
| Approach | Role | Upside | Architecture | Trade-offs | Recommendation |
|
|
50
|
-
|
|
51
|
-
| A | baseline | modest | | | |
|
|
52
|
-
| B | challenger | high | | | |
|
|
67
|
+
| Approach | Role | Upside | Architecture | Trade-offs | Reuses | Recommendation |
|
|
68
|
+
|---|---|---|---|---|---|---|
|
|
69
|
+
| A | baseline | modest | | | | |
|
|
70
|
+
| B | challenger | high | | | | |
|
|
71
|
+
|
|
72
|
+
> Role values: \`baseline\` | \`challenger\` | \`wild-card\`. Upside values: \`low\` | \`modest\` | \`high\` | \`higher\`. Exactly one row must be a \`challenger\` with \`high\` or \`higher\` upside.
|
|
53
73
|
|
|
54
74
|
## Approach Reaction
|
|
55
75
|
- Closest option:
|
|
@@ -62,6 +82,9 @@ export const ARTIFACT_TEMPLATES = {
|
|
|
62
82
|
- **Approval:** pending
|
|
63
83
|
- **Next-stage handoff:** On standard track, hand this to \`scope\`; on medium track, hand this directly to \`spec\` with explicit requirements/constraints.
|
|
64
84
|
|
|
85
|
+
## Not Doing
|
|
86
|
+
- (3-5 things this brainstorm is *not* committing to — distinct from \`Deferred\`. These will not appear in scope unless the user explicitly opts in.)
|
|
87
|
+
|
|
65
88
|
${SEED_SHELF_SECTION}
|
|
66
89
|
|
|
67
90
|
## Design
|
|
@@ -69,6 +92,12 @@ ${SEED_SHELF_SECTION}
|
|
|
69
92
|
- **Key components:**
|
|
70
93
|
- **Data flow:**
|
|
71
94
|
|
|
95
|
+
## Visual Companion
|
|
96
|
+
- (compact ASCII/Mermaid diagram for medium+ complexity, or one-line justification for omission.)
|
|
97
|
+
|
|
98
|
+
## Self-Review Notes
|
|
99
|
+
- (list patches applied to this artifact during self-review, or \`- None.\`)
|
|
100
|
+
|
|
72
101
|
## Assumptions and Open Questions
|
|
73
102
|
- **Assumptions:**
|
|
74
103
|
- **Open questions (or "None"):**
|
|
@@ -101,9 +130,13 @@ ${SEED_SHELF_SECTION}
|
|
|
101
130
|
- Four paths per data flow:
|
|
102
131
|
|
|
103
132
|
## Premise Challenge
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
133
|
+
| Question | Answer (take a position) | Evidence / leverage |
|
|
134
|
+
|---|---|---|
|
|
135
|
+
| Right problem? | | |
|
|
136
|
+
| Direct path? | | |
|
|
137
|
+
| What if we do nothing? | | |
|
|
138
|
+
| Existing-code leverage? | | |
|
|
139
|
+
| Reversibility cost? | | |
|
|
107
140
|
|
|
108
141
|
## Dream State Mapping
|
|
109
142
|
- CURRENT STATE:
|
|
@@ -198,7 +231,9 @@ ${SEED_SHELF_SECTION}
|
|
|
198
231
|
- Unresolved decisions (or \`None\`):
|
|
199
232
|
|
|
200
233
|
## Scope Summary
|
|
201
|
-
- Selected mode:
|
|
234
|
+
- Selected mode: (one of \`SCOPE EXPANSION\` | \`SELECTIVE EXPANSION\` | \`HOLD SCOPE\` | \`SCOPE REDUCTION\`)
|
|
235
|
+
- Strongest challenges resolved:
|
|
236
|
+
- Recommended path:
|
|
202
237
|
- Accepted scope:
|
|
203
238
|
- Deferred:
|
|
204
239
|
- Explicitly excluded:
|
|
@@ -19,7 +19,6 @@ import { runTddLoopStatusCommand } from "./tdd-loop-status.js";
|
|
|
19
19
|
import { runTddRedEvidenceCommand } from "./tdd-red-evidence.js";
|
|
20
20
|
import { extractReviewLoopEnvelopeFromArtifact } from "../content/review-loop.js";
|
|
21
21
|
const AUTO_REVIEW_LOOP_GATE_BY_STAGE = {
|
|
22
|
-
scope: "scope_user_approved",
|
|
23
22
|
design: "design_architecture_locked"
|
|
24
23
|
};
|
|
25
24
|
function unique(values) {
|
|
@@ -163,6 +162,30 @@ function validateReviewLoopGateEvidence(stage, evidence) {
|
|
|
163
162
|
}
|
|
164
163
|
return null;
|
|
165
164
|
}
|
|
165
|
+
function validateUserApprovalEvidence(evidence) {
|
|
166
|
+
const normalized = evidence.trim();
|
|
167
|
+
if (normalized.length === 0) {
|
|
168
|
+
return "must cite explicit user approval.";
|
|
169
|
+
}
|
|
170
|
+
const reviewLoopEnvelope = (() => {
|
|
171
|
+
try {
|
|
172
|
+
return pickReviewLoopEnvelope(JSON.parse(normalized));
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
})();
|
|
178
|
+
if (reviewLoopEnvelope) {
|
|
179
|
+
return "must cite explicit user approval; review-loop evidence is outside-voice evidence, not user approval.";
|
|
180
|
+
}
|
|
181
|
+
if (/\b(?:approved|approval|user approved|confirmed|accepted|yes|ok)\b/iu.test(normalized)) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
if (/\b(?:утвержд(?:аю|ено|ен|ена)|подтвержд(?:аю|ено|ен|ена)|соглас(?:ен|на|овано)|да|ок|принято)\b/iu.test(normalized)) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
return "must cite explicit user approval (for example `user approved the scope contract` or `пользователь утвердил scope`).";
|
|
188
|
+
}
|
|
166
189
|
// Per-gate validators keyed by `${stage}:${gateId}`. Returning a non-null
|
|
167
190
|
// string surfaces the reason as an `advance-stage` failure so evidence is
|
|
168
191
|
// guaranteed to carry the structural breadcrumbs downstream tooling
|
|
@@ -186,7 +209,7 @@ const GATE_EVIDENCE_VALIDATORS = {
|
|
|
186
209
|
}
|
|
187
210
|
return null;
|
|
188
211
|
},
|
|
189
|
-
"scope:scope_user_approved": (evidence) =>
|
|
212
|
+
"scope:scope_user_approved": (evidence) => validateUserApprovalEvidence(evidence),
|
|
190
213
|
"design:design_architecture_locked": (evidence) => validateReviewLoopGateEvidence("design", evidence)
|
|
191
214
|
};
|
|
192
215
|
function validateGateEvidenceShape(stage, gateId, evidence) {
|