cclaw-cli 6.14.4 → 7.0.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.
- package/README.md +0 -2
- package/dist/artifact-linter/brainstorm.js +1 -1
- package/dist/artifact-linter/design.js +2 -2
- package/dist/artifact-linter/findings-dedup.js +1 -1
- package/dist/artifact-linter/plan.js +6 -6
- package/dist/artifact-linter/review-army.d.ts +1 -1
- package/dist/artifact-linter/review-army.js +1 -1
- package/dist/artifact-linter/scope.js +6 -6
- package/dist/artifact-linter/shared.d.ts +37 -73
- package/dist/artifact-linter/shared.js +30 -37
- package/dist/artifact-linter/spec.js +1 -1
- package/dist/artifact-linter/tdd.d.ts +20 -33
- package/dist/artifact-linter/tdd.js +89 -639
- package/dist/artifact-linter.js +11 -32
- package/dist/cli.js +1 -1
- package/dist/config.js +1 -1
- package/dist/constants.js +1 -1
- package/dist/content/core-agents.d.ts +8 -26
- package/dist/content/core-agents.js +48 -94
- package/dist/content/examples.d.ts +1 -1
- package/dist/content/examples.js +4 -4
- package/dist/content/hooks.js +62 -149
- package/dist/content/idea.js +2 -2
- package/dist/content/iron-laws.js +1 -1
- package/dist/content/node-hooks.js +2 -2
- package/dist/content/skills-elicitation.js +2 -2
- package/dist/content/skills.d.ts +4 -6
- package/dist/content/skills.js +14 -53
- package/dist/content/stage-schema.d.ts +3 -3
- package/dist/content/stage-schema.js +8 -46
- package/dist/content/stages/brainstorm.js +5 -5
- package/dist/content/stages/plan.js +2 -2
- package/dist/content/stages/review.js +1 -1
- package/dist/content/stages/schema-types.d.ts +1 -1
- package/dist/content/stages/scope.js +1 -1
- package/dist/content/stages/spec.js +2 -2
- package/dist/content/stages/tdd.js +43 -108
- package/dist/content/start-command.js +3 -3
- package/dist/content/subagent-context-skills.js +5 -3
- package/dist/content/subagents.js +13 -74
- package/dist/content/templates.d.ts +6 -6
- package/dist/content/templates.js +23 -24
- package/dist/content/utility-skills.d.ts +1 -1
- package/dist/content/utility-skills.js +1 -1
- package/dist/delegation.d.ts +79 -139
- package/dist/delegation.js +83 -215
- package/dist/early-loop.js +1 -1
- package/dist/flow-state.d.ts +24 -129
- package/dist/flow-state.js +5 -30
- package/dist/gate-evidence.d.ts +2 -7
- package/dist/gate-evidence.js +2 -59
- package/dist/harness-adapters.d.ts +1 -1
- package/dist/harness-adapters.js +11 -10
- package/dist/install.js +28 -460
- package/dist/internal/advance-stage/advance.d.ts +5 -5
- package/dist/internal/advance-stage/advance.js +9 -24
- package/dist/internal/advance-stage/parsers.d.ts +1 -1
- package/dist/internal/advance-stage/review-loop.d.ts +1 -1
- package/dist/internal/advance-stage/review-loop.js +3 -3
- package/dist/internal/advance-stage/start-flow.js +1 -3
- package/dist/internal/advance-stage.js +4 -23
- package/dist/internal/cohesion-contract-stub.d.ts +8 -13
- package/dist/internal/cohesion-contract-stub.js +18 -24
- package/dist/internal/flow-state-repair.d.ts +1 -1
- package/dist/internal/plan-split-waves.d.ts +18 -21
- package/dist/internal/plan-split-waves.js +16 -19
- package/dist/internal/wave-status.d.ts +3 -6
- package/dist/internal/wave-status.js +5 -27
- package/dist/policy.js +1 -1
- package/dist/run-persistence.js +10 -44
- package/dist/runtime/run-hook.mjs +3 -3
- package/dist/track-heuristics.js +1 -1
- package/dist/types.d.ts +2 -2
- package/package.json +1 -1
- package/dist/integration-fanin.d.ts +0 -44
- package/dist/integration-fanin.js +0 -180
- package/dist/internal/set-checkpoint-mode.d.ts +0 -16
- package/dist/internal/set-checkpoint-mode.js +0 -72
- package/dist/internal/set-integration-overseer-mode.d.ts +0 -14
- package/dist/internal/set-integration-overseer-mode.js +0 -69
- package/dist/internal/set-worktree-mode.d.ts +0 -10
- package/dist/internal/set-worktree-mode.js +0 -28
- package/dist/worktree-manager.d.ts +0 -50
- package/dist/worktree-manager.js +0 -136
- package/dist/worktree-types.d.ts +0 -36
- package/dist/worktree-types.js +0 -6
package/README.md
CHANGED
|
@@ -64,8 +64,6 @@ AI coding sessions fail when decisions live only in chat. cclaw puts the operati
|
|
|
64
64
|
archive/ archived run snapshots (durable closeout proof)
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
Legacy `.cclaw/runs/` directories are only auto-removed when empty. If the directory still contains data, migrate it manually to `.cclaw/archive/`.
|
|
68
|
-
|
|
69
67
|
That gives you:
|
|
70
68
|
|
|
71
69
|
- **One path** from idea to ship, with one user-chosen discovery mode (`lean`, `guided`, `deep`) and internal `quick` / `medium` / `standard` tracks.
|
|
@@ -307,7 +307,7 @@ export async function lintBrainstormStage(ctx) {
|
|
|
307
307
|
findings.push({
|
|
308
308
|
section: "brainstorm.idea_evidence_carry_forward",
|
|
309
309
|
required: true,
|
|
310
|
-
rule: "[P1] brainstorm.idea_evidence_carry_forward — when `flow-state.interactionHints.brainstorm.fromIdeaArtifact` is set
|
|
310
|
+
rule: "[P1] brainstorm.idea_evidence_carry_forward — when `flow-state.interactionHints.brainstorm.fromIdeaArtifact` is set, the brainstorm artifact MUST include `## Idea Evidence Carry-forward` citing the idea artifact path and chosen `I-#`. Reuse divergent + critique + rank work from `/cc-ideate` as the `baseline` Approach; only newly generate the higher-upside challenger row(s).",
|
|
311
311
|
found: ok,
|
|
312
312
|
details: ok
|
|
313
313
|
? `Idea Evidence Carry-forward cites ${ideaHint.fromIdeaArtifact}${ideaHint.fromIdeaCandidateId ? ` (${ideaHint.fromIdeaCandidateId})` : ""}.`
|
|
@@ -111,7 +111,7 @@ async function resolveDesignDiagramTier(projectRoot, track, designRaw) {
|
|
|
111
111
|
return { tier: "standard", source: "default:standard" };
|
|
112
112
|
}
|
|
113
113
|
/**
|
|
114
|
-
*
|
|
114
|
+
* parenthetical suffixes that the audit strips
|
|
115
115
|
* from a Codebase Investigation filename cell BEFORE attempting
|
|
116
116
|
* `fs.stat`. The user's quick-tier test wrote `index.html (new)` in
|
|
117
117
|
* the table, and the linter then tried to stat the literal string
|
|
@@ -157,7 +157,7 @@ export function normalizeCodebaseInvestigationFileRef(value, notesCell) {
|
|
|
157
157
|
return null;
|
|
158
158
|
if (/^(?:file|n\/a|none|\(none\)|tbd|\?)$/iu.test(stripped))
|
|
159
159
|
return null;
|
|
160
|
-
// Notes column may carry an explicit `skip:` marker
|
|
160
|
+
// Notes column may carry an explicit `skip:` marker.
|
|
161
161
|
if (/(?:^|\s|\|)skip\s*:/iu.test(notesCell))
|
|
162
162
|
skip = true;
|
|
163
163
|
return { filename: stripped, raw: cleanedFull, newFile, skip };
|
|
@@ -4,7 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { RUNTIME_ROOT } from "../constants.js";
|
|
5
5
|
import { ensureDir, exists, withDirectoryLock, writeFileSafe } from "../fs-utils.js";
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* linter-dedup cache. The linter persists a per-stage
|
|
8
8
|
* fingerprint of each finding between runs so authors can tell at a
|
|
9
9
|
* glance what's `new`, `repeat`, or `resolved` relative to the last run.
|
|
10
10
|
*
|
|
@@ -6,7 +6,7 @@ import fs from "node:fs/promises";
|
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { PLAN_SPLIT_SMALL_PLAN_THRESHOLD, parseImplementationUnits, parseImplementationUnitParallelFields } from "../internal/plan-split-waves.js";
|
|
8
8
|
export async function lintPlanStage(ctx) {
|
|
9
|
-
const { projectRoot, track, raw, absFile, sections, findings, parsedFrontmatter, brainstormShortCircuitBody, brainstormShortCircuitActivated, staleDiagramAuditEnabled, isTrivialOverride
|
|
9
|
+
const { projectRoot, track, raw, absFile, sections, findings, parsedFrontmatter, brainstormShortCircuitBody, brainstormShortCircuitActivated, staleDiagramAuditEnabled, isTrivialOverride } = ctx;
|
|
10
10
|
evaluateInvestigationTrace(ctx, "Implementation Units");
|
|
11
11
|
const strictPlanGuards = parsedFrontmatter.hasFrontmatter ||
|
|
12
12
|
headingPresent(sections, "Plan Quality Scan") ||
|
|
@@ -116,7 +116,7 @@ export async function lintPlanStage(ctx) {
|
|
|
116
116
|
? "No forbidden placeholder tokens detected outside the rule section."
|
|
117
117
|
: `Detected forbidden token(s) elsewhere in plan: ${filteredPlanHits.join(", ")}.`
|
|
118
118
|
});
|
|
119
|
-
//
|
|
119
|
+
// advisory `plan_too_large_no_waves`. Fires when a
|
|
120
120
|
// standard-track plan has more than the wave-split threshold of
|
|
121
121
|
// implementation units AND the wave-plans/ directory is empty.
|
|
122
122
|
// Linter advisories never block stage-complete (`required: false`),
|
|
@@ -222,7 +222,7 @@ export async function lintPlanStage(ctx) {
|
|
|
222
222
|
const planUnits = parseImplementationUnits(raw);
|
|
223
223
|
const parallelMetaApplies = strictPlanGuards && planUnits.length > 0;
|
|
224
224
|
if (parallelMetaApplies) {
|
|
225
|
-
const metaRulesRequired =
|
|
225
|
+
const metaRulesRequired = true;
|
|
226
226
|
const missingDepends = [];
|
|
227
227
|
const missingPaths = [];
|
|
228
228
|
const missingParallelMeta = [];
|
|
@@ -241,7 +241,7 @@ export async function lintPlanStage(ctx) {
|
|
|
241
241
|
findings.push({
|
|
242
242
|
section: "plan_units_missing_dependsOn",
|
|
243
243
|
required: metaRulesRequired,
|
|
244
|
-
rule: "Every implementation unit must declare `dependsOn:`
|
|
244
|
+
rule: "Every implementation unit must declare `dependsOn:` — use comma-separated unit ids or `none`.",
|
|
245
245
|
found: missingDepends.length === 0,
|
|
246
246
|
details: missingDepends.length === 0
|
|
247
247
|
? "All implementation units declare dependsOn."
|
|
@@ -250,7 +250,7 @@ export async function lintPlanStage(ctx) {
|
|
|
250
250
|
findings.push({
|
|
251
251
|
section: "plan_units_missing_claimedPaths",
|
|
252
252
|
required: metaRulesRequired,
|
|
253
|
-
rule: "Every implementation unit must declare explicit `claimedPaths:` predictions for parallel scheduling
|
|
253
|
+
rule: "Every implementation unit must declare explicit `claimedPaths:` predictions for parallel scheduling.",
|
|
254
254
|
found: missingPaths.length === 0,
|
|
255
255
|
details: missingPaths.length === 0
|
|
256
256
|
? "All implementation units declare claimedPaths."
|
|
@@ -259,7 +259,7 @@ export async function lintPlanStage(ctx) {
|
|
|
259
259
|
findings.push({
|
|
260
260
|
section: "plan_units_missing_parallel_metadata",
|
|
261
261
|
required: metaRulesRequired,
|
|
262
|
-
rule: "Every implementation unit must declare `parallelizable:` and `riskTier:` (low|standard|high)
|
|
262
|
+
rule: "Every implementation unit must declare `parallelizable:` and `riskTier:` (low|standard|high).",
|
|
263
263
|
found: missingParallelMeta.length === 0,
|
|
264
264
|
details: missingParallelMeta.length === 0
|
|
265
265
|
? "All implementation units carry parallelizable + riskTier."
|
|
@@ -36,7 +36,7 @@ export interface ReviewTddDuplicationResult {
|
|
|
36
36
|
reviewArtifactExists: boolean;
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
* Cross-artifact duplication guard
|
|
39
|
+
* Cross-artifact duplication guard.
|
|
40
40
|
*
|
|
41
41
|
* When the same finding ID (`F-NN`) appears in both
|
|
42
42
|
* `06-tdd.md > Per-Slice Review` and `07-review-army.json`, the
|
|
@@ -358,7 +358,7 @@ function extractTddPerSliceFindings(perSliceBody) {
|
|
|
358
358
|
return rows;
|
|
359
359
|
}
|
|
360
360
|
/**
|
|
361
|
-
* Cross-artifact duplication guard
|
|
361
|
+
* Cross-artifact duplication guard.
|
|
362
362
|
*
|
|
363
363
|
* When the same finding ID (`F-NN`) appears in both
|
|
364
364
|
* `06-tdd.md > Per-Slice Review` and `07-review-army.json`, the
|
|
@@ -35,7 +35,7 @@ export async function lintScopeStage(ctx) {
|
|
|
35
35
|
}
|
|
36
36
|
const strategistRequired = selectedScopeMode === "SCOPE EXPANSION" || selectedScopeMode === "SELECTIVE EXPANSION";
|
|
37
37
|
if (strategistRequired) {
|
|
38
|
-
//
|
|
38
|
+
// for `track === "quick"` (lite-tier) or
|
|
39
39
|
// `taskClass === "software-bugfix"`, the Expansion Strategist
|
|
40
40
|
// delegation requirement is dropped entirely. The user's
|
|
41
41
|
// 3-file static landing page hit this gate without any
|
|
@@ -50,7 +50,7 @@ export async function lintScopeStage(ctx) {
|
|
|
50
50
|
found: true,
|
|
51
51
|
details: `Product-discovery delegation requirement skipped for track="${track}"` +
|
|
52
52
|
(taskClass ? `, taskClass="${taskClass}"` : "") +
|
|
53
|
-
` (
|
|
53
|
+
` (lite-tier escape; selectedMode=${selectedScopeMode}).`
|
|
54
54
|
});
|
|
55
55
|
// Best-effort audit; we read the flow-state runId here
|
|
56
56
|
// because StageLintContext does not surface it directly.
|
|
@@ -103,7 +103,7 @@ export async function lintScopeStage(ctx) {
|
|
|
103
103
|
}
|
|
104
104
|
if (sectionBodyByHeadingPrefix(sections, "Locked Decisions") !== null) {
|
|
105
105
|
// D-XX IDs are the stable contract. The legacy LD#<sha8> hash anchor
|
|
106
|
-
// check was removed in
|
|
106
|
+
// check was removed in it caused agents to spam
|
|
107
107
|
// shell hash commands when shifting decision rows around, and provided
|
|
108
108
|
// no signal beyond the D-XX uniqueness check below.
|
|
109
109
|
const listDecisionLines = lockedDecisionsBody
|
|
@@ -141,18 +141,18 @@ export async function lintScopeStage(ctx) {
|
|
|
141
141
|
findings.push({
|
|
142
142
|
section: "Locked Decisions ID Integrity",
|
|
143
143
|
required: false,
|
|
144
|
-
rule: "Locked Decisions section must list each decision with a unique stable D-XX ID.
|
|
144
|
+
rule: "Locked Decisions section must list each decision with a unique stable D-XX ID.",
|
|
145
145
|
found: issues.length === 0,
|
|
146
146
|
details: issues.length === 0
|
|
147
147
|
? `${rowDecisionIds.length} decision ID(s) recorded with no duplicates.`
|
|
148
148
|
: issues.join("; ")
|
|
149
149
|
});
|
|
150
150
|
}
|
|
151
|
-
//
|
|
151
|
+
// scope no longer owns architecture-tier alternatives
|
|
152
152
|
// (`## Implementation Alternatives` was removed from the scope template
|
|
153
153
|
// and stage schema). Design OWNS the architecture-tier decision via
|
|
154
154
|
// `## Architecture Decision Record (ADR)` and `## Engineering Lock`.
|
|
155
155
|
// The legacy linter rule `Implementation Alternatives Recommendation`
|
|
156
|
-
// was removed in
|
|
156
|
+
// was removed in if a legacy artifact still has the section,
|
|
157
157
|
// it is now treated as informational only.
|
|
158
158
|
}
|
|
@@ -6,14 +6,14 @@ import { type DiscoveryMode, type FlowStage, type FlowTrack } from "../types.js"
|
|
|
6
6
|
*/
|
|
7
7
|
export declare const ELICITATION_STAGES: ReadonlySet<FlowStage>;
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* Language-neutral forcing-question topic descriptor.
|
|
10
10
|
*
|
|
11
|
-
* Each forcing-question row in a stage's checklist
|
|
11
|
+
* Each forcing-question row in a stage's checklist declares topics as
|
|
12
12
|
* `id: human-readable label` pairs (e.g. `pain: what pain are we solving`).
|
|
13
13
|
* The `id` (kebab-case ASCII) is the machine-key authors stamp on Q&A Log
|
|
14
14
|
* rows via `[topic:<id>]` so the linter can verify coverage in ANY natural
|
|
15
|
-
* language (RU/EN/UA/etc.).
|
|
16
|
-
* because it silently mis-
|
|
15
|
+
* language (RU/EN/UA/etc.). English keyword detection is intentionally
|
|
16
|
+
* absent because it silently mis-reports convergence on RU/UA Q&A.
|
|
17
17
|
*/
|
|
18
18
|
export interface ForcingQuestionTopic {
|
|
19
19
|
id: string;
|
|
@@ -41,7 +41,7 @@ export interface QaLogFloorResult {
|
|
|
41
41
|
count: number;
|
|
42
42
|
/**
|
|
43
43
|
* Legacy field, retained for harness UI compatibility. Always 0 in
|
|
44
|
-
*
|
|
44
|
+
* the convergence floor no longer enforces a fixed count.
|
|
45
45
|
* Harness can still surface `questionBudgetHint(track, stage).recommended`
|
|
46
46
|
* as a soft hint, but it is NOT tied to gate blocking.
|
|
47
47
|
*/
|
|
@@ -50,7 +50,7 @@ export interface QaLogFloorResult {
|
|
|
50
50
|
hasStopSignal: boolean;
|
|
51
51
|
/**
|
|
52
52
|
* Legacy field, retained for harness UI compatibility. Always false in
|
|
53
|
-
*
|
|
53
|
+
* convergence semantics replaced the lite-tier short-circuit.
|
|
54
54
|
*/
|
|
55
55
|
liteShortCircuit: boolean;
|
|
56
56
|
/** Whether `--skip-questions` flag downgraded the finding to advisory. */
|
|
@@ -72,9 +72,9 @@ export interface QaLogFloorResult {
|
|
|
72
72
|
* Parse a single checklist row into the list of forcing-question topic
|
|
73
73
|
* descriptors it declares. Returns `null` when the row is not a
|
|
74
74
|
* forcing-questions header. Throws when the header is found but its
|
|
75
|
-
* body does not match the
|
|
76
|
-
*
|
|
77
|
-
*
|
|
75
|
+
* body does not match the `id: topic; id: topic; ...` syntax — authors
|
|
76
|
+
* fix the stage definition rather than silently ship un-coverable
|
|
77
|
+
* topics.
|
|
78
78
|
*
|
|
79
79
|
* Exposed for unit tests that exercise the parser without depending on
|
|
80
80
|
* the live stage schema.
|
|
@@ -83,9 +83,9 @@ export declare function parseForcingQuestionsRow(row: string, context?: string):
|
|
|
83
83
|
/**
|
|
84
84
|
* Extract forcing-question topics from a stage's checklist.
|
|
85
85
|
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
86
|
+
* Only the `id: topic; id: topic; ...` syntax is accepted. Throws when
|
|
87
|
+
* the syntax is malformed so authors fix the stage definition rather
|
|
88
|
+
* than silently shipping un-coverable topics.
|
|
89
89
|
*
|
|
90
90
|
* Returns empty array when no forcing-questions row is present (caller
|
|
91
91
|
* treats absence as "no forcing requirement" — convergence falls back
|
|
@@ -110,10 +110,9 @@ export declare function extractForcingQuestions(stage: FlowStage): ForcingQuesti
|
|
|
110
110
|
* `skipQuestionsAdvisory` is true (linter treats as non-blocking).
|
|
111
111
|
* - No forcing-questions row in the checklist and ≥1 substantive row.
|
|
112
112
|
*
|
|
113
|
-
*
|
|
114
|
-
* `
|
|
115
|
-
*
|
|
116
|
-
* liteShortCircuit false).
|
|
113
|
+
* `[topic:<id>]` is the sole topic-coverage signal. The `min` and
|
|
114
|
+
* `liteShortCircuit` fields stay for harness compatibility (min is
|
|
115
|
+
* always 0; liteShortCircuit false).
|
|
117
116
|
*/
|
|
118
117
|
export declare function evaluateQaLogFloor(qaLogBody: string | null, track: FlowTrack, stage: FlowStage, options?: QaLogFloorOptions): QaLogFloorResult;
|
|
119
118
|
export interface LintFinding {
|
|
@@ -284,13 +283,13 @@ export interface InteractionEdgeCaseRequirement {
|
|
|
284
283
|
}
|
|
285
284
|
export declare const INTERACTION_EDGE_CASE_REQUIREMENTS: readonly InteractionEdgeCaseRequirement[];
|
|
286
285
|
/**
|
|
287
|
-
*
|
|
286
|
+
* context for `validateInteractionEdgeCaseMatrix`.
|
|
288
287
|
*
|
|
289
|
-
*
|
|
290
|
-
* "Interaction Edge Case row \"nav-away-mid-request\" must mark
|
|
291
|
-
* Handled? as yes/no" because
|
|
292
|
-
*
|
|
293
|
-
* D-12)`.
|
|
288
|
+
* Background: a quick-tier test of a 3-file static landing page used
|
|
289
|
+
* to trip "Interaction Edge Case row \"nav-away-mid-request\" must mark
|
|
290
|
+
* Handled? as yes/no" because the author wrote `N/A` (no network at
|
|
291
|
+
* all), then `unhandled must reference a deferred item id (for example
|
|
292
|
+
* D-12)`. Two relaxations apply:
|
|
294
293
|
*
|
|
295
294
|
* 1. `N/A — <reason>` (em-dash + free-text reason) is now an
|
|
296
295
|
* accepted Handled? value. The reason replaces the D-XX
|
|
@@ -326,7 +325,7 @@ export declare const DIAGRAM_ARROW_PATTERN: RegExp;
|
|
|
326
325
|
export declare const DIAGRAM_FAILURE_EDGE_PATTERN: RegExp;
|
|
327
326
|
export declare const DIAGRAM_GENERIC_NODE_PATTERN: RegExp;
|
|
328
327
|
/**
|
|
329
|
-
*
|
|
328
|
+
* external-dependency keywords that trigger the
|
|
330
329
|
* failure-edge requirement. The architecture diagram is allowed to
|
|
331
330
|
* omit failure edges only when ALL of:
|
|
332
331
|
* - Failure Mode Table has zero rows.
|
|
@@ -346,7 +345,7 @@ export declare function diagramEdgeLines(sectionBody: string): string[];
|
|
|
346
345
|
export declare function hasFailureEdgeInDiagram(sectionBody: string): boolean;
|
|
347
346
|
export declare function hasLabeledDiagramArrow(lines: string[]): boolean;
|
|
348
347
|
/**
|
|
349
|
-
*
|
|
348
|
+
* accepted async edge patterns. Returns true when
|
|
350
349
|
* a line carries any of:
|
|
351
350
|
*
|
|
352
351
|
* - `-.->`, `-->>`, `~~>` (mermaid dotted/messaging arrows)
|
|
@@ -361,7 +360,7 @@ export declare function hasLabeledDiagramArrow(lines: string[]): boolean;
|
|
|
361
360
|
*/
|
|
362
361
|
export declare function hasAsyncDiagramEdge(lines: string[]): boolean;
|
|
363
362
|
/**
|
|
364
|
-
*
|
|
363
|
+
* accepted sync edge patterns. Returns true when a
|
|
365
364
|
* line carries any of:
|
|
366
365
|
*
|
|
367
366
|
* - `\bsync\b` text token (label-based)
|
|
@@ -373,7 +372,7 @@ export declare function hasAsyncDiagramEdge(lines: string[]): boolean;
|
|
|
373
372
|
*/
|
|
374
373
|
export declare function hasSyncDiagramEdge(lines: string[]): boolean;
|
|
375
374
|
/**
|
|
376
|
-
*
|
|
375
|
+
* exact accepted-pattern list shown in the error
|
|
377
376
|
* message when sync/async distinction fails. Keep in sync with
|
|
378
377
|
* `hasAsyncDiagramEdge` / `hasSyncDiagramEdge` above.
|
|
379
378
|
*/
|
|
@@ -387,7 +386,7 @@ export interface ArchitectureDiagramValidationResult {
|
|
|
387
386
|
details: string;
|
|
388
387
|
}
|
|
389
388
|
/**
|
|
390
|
-
*
|
|
389
|
+
* Architecture Diagram structural check.
|
|
391
390
|
*
|
|
392
391
|
* Promoted out of `validateSectionBody` so it can take a `sections`
|
|
393
392
|
* map and conditionally enforce the failure-edge rule based on
|
|
@@ -396,7 +395,7 @@ export interface ArchitectureDiagramValidationResult {
|
|
|
396
395
|
*/
|
|
397
396
|
export declare function validateArchitectureDiagram(sectionBody: string, context?: ArchitectureDiagramValidationContext): ArchitectureDiagramValidationResult;
|
|
398
397
|
/**
|
|
399
|
-
*
|
|
398
|
+
* pointer-mode evidence acceptance. RED/GREEN sections may
|
|
400
399
|
* substitute pasted stdout with a single line of the form
|
|
401
400
|
* `Evidence: <relative-or-abs-path>` or `Evidence: spanId:<id>`. The
|
|
402
401
|
* validator alone cannot reach the filesystem or delegation ledger
|
|
@@ -412,11 +411,11 @@ export interface TddEvidencePointerOptions {
|
|
|
412
411
|
*/
|
|
413
412
|
pointerSatisfied?: boolean;
|
|
414
413
|
/**
|
|
415
|
-
*
|
|
414
|
+
* true when `delegation-events.jsonl` carries at least
|
|
416
415
|
* one slice-tagged event for the current run with the matching phase
|
|
417
416
|
* (`phase=red` for RED, `phase=green` for GREEN) and a non-empty
|
|
418
417
|
* `evidenceRefs` array. Phase events are the new source of truth in
|
|
419
|
-
*
|
|
418
|
+
* the markdown evidence block is auto-satisfied without
|
|
420
419
|
* requiring hand-pasted stdout content.
|
|
421
420
|
*/
|
|
422
421
|
phaseEventsSatisfied?: boolean;
|
|
@@ -491,7 +490,7 @@ export declare function parseLearningSeedEntry(raw: unknown, index: number): {
|
|
|
491
490
|
};
|
|
492
491
|
export declare function parseLearningsSection(sectionBody: string): LearningsParseResult;
|
|
493
492
|
/**
|
|
494
|
-
*
|
|
493
|
+
* file-path / reference detector for the
|
|
495
494
|
* `investigation_path_first_missing` advisory rule.
|
|
496
495
|
*
|
|
497
496
|
* The detector is intentionally permissive: it only needs to recognize
|
|
@@ -530,7 +529,7 @@ export interface InvestigationTraceFinding {
|
|
|
530
529
|
*/
|
|
531
530
|
export declare function checkInvestigationTrace(sectionBody: string | null): InvestigationTraceFinding | null;
|
|
532
531
|
/**
|
|
533
|
-
*
|
|
532
|
+
* advisory rule wired into the brainstorm / scope /
|
|
534
533
|
* design / tdd / plan / review linters.
|
|
535
534
|
*
|
|
536
535
|
* Behavior contract:
|
|
@@ -567,14 +566,14 @@ export declare function collectPatternHits(text: string, patterns: Array<{
|
|
|
567
566
|
}>): string[];
|
|
568
567
|
export interface ValidateSectionBodyContext {
|
|
569
568
|
/**
|
|
570
|
-
*
|
|
569
|
+
* optional H2 sections map for cross-section
|
|
571
570
|
* checks (e.g. Architecture Diagram failure-edge enforcement gates
|
|
572
571
|
* on Failure Mode Table presence). When omitted, cross-section
|
|
573
572
|
* checks fall back to legacy blanket enforcement.
|
|
574
573
|
*/
|
|
575
574
|
sections?: H2SectionMap | null;
|
|
576
575
|
/**
|
|
577
|
-
*
|
|
576
|
+
* when true, lite-tier-only relaxations apply.
|
|
578
577
|
* Currently used by the Interaction Edge Case matrix to demote
|
|
579
578
|
* network-dependent mandatory rows to advisory when the design has
|
|
580
579
|
* no Failure Mode Table rows and no external-dependency keywords
|
|
@@ -582,7 +581,7 @@ export interface ValidateSectionBodyContext {
|
|
|
582
581
|
*/
|
|
583
582
|
liteTier?: boolean;
|
|
584
583
|
/**
|
|
585
|
-
*
|
|
584
|
+
* pre-resolved RED/GREEN Evidence pointer state. The
|
|
586
585
|
* artifact linter resolves `Evidence: <path|spanId:...>` lines and
|
|
587
586
|
* inspects the TDD slice sidecar before invoking
|
|
588
587
|
* `validateSectionBody`; the resulting booleans here let the
|
|
@@ -621,7 +620,7 @@ export interface StageLintContext {
|
|
|
621
620
|
*/
|
|
622
621
|
activeStageFlags: string[];
|
|
623
622
|
/**
|
|
624
|
-
*
|
|
623
|
+
* task class for the active run, mirrored from
|
|
625
624
|
* `flow-state.json::taskClass`. `null` when not classified. Stage
|
|
626
625
|
* linters read this together with `track` via
|
|
627
626
|
* `shouldDemoteArtifactValidationByTrack` to demote advanced
|
|
@@ -631,42 +630,7 @@ export interface StageLintContext {
|
|
|
631
630
|
*/
|
|
632
631
|
taskClass: "software-standard" | "software-trivial" | "software-bugfix" | null;
|
|
633
632
|
/**
|
|
634
|
-
*
|
|
635
|
-
* for legacy continuation projects (hox-style).
|
|
633
|
+
* `flow-state.json::packageVersion` when present.
|
|
636
634
|
*/
|
|
637
|
-
|
|
638
|
-
/**
|
|
639
|
-
* v6.13.0 — effective worktree execution mode for TDD linters.
|
|
640
|
-
*/
|
|
641
|
-
worktreeExecutionMode: "single-tree" | "worktree-first";
|
|
642
|
-
/**
|
|
643
|
-
* v6.14.0 — effective TDD checkpoint mode. `per-slice` enforces
|
|
644
|
-
* RED-before-GREEN per slice (the default for new projects);
|
|
645
|
-
* `global-red` keeps the v6.12/v6.13 wave-batch barrier (auto-applied
|
|
646
|
-
* for `legacyContinuation: true` projects on `cclaw-cli sync`).
|
|
647
|
-
*/
|
|
648
|
-
tddCheckpointMode: "per-slice" | "global-red";
|
|
649
|
-
/**
|
|
650
|
-
* v6.14.0 — effective integration-overseer dispatch mode.
|
|
651
|
-
* `conditional` runs the overseer only when
|
|
652
|
-
* `integrationCheckRequired()` returns `required: true`; `always`
|
|
653
|
-
* preserves the v6.13 behavior of running it on every multi-slice
|
|
654
|
-
* wave.
|
|
655
|
-
*/
|
|
656
|
-
integrationOverseerMode: "conditional" | "always";
|
|
657
|
-
/**
|
|
658
|
-
* v6.14.2 — historical cutover marker (`flow-state.json::tddCutoverSliceId`).
|
|
659
|
-
* Empty string when not set. Used by the `tdd_cutover_misread_warning`
|
|
660
|
-
* advisory rule to detect controllers that mistake the historical
|
|
661
|
-
* marker for an active-slice pointer.
|
|
662
|
-
*/
|
|
663
|
-
tddCutoverSliceId: string;
|
|
664
|
-
/**
|
|
665
|
-
* v6.14.2 — worktree-first boundary
|
|
666
|
-
* (`flow-state.json::tddWorktreeCutoverSliceId`). Empty string when
|
|
667
|
-
* not set. Linters that fire on closed worktree slices use this
|
|
668
|
-
* boundary (with a fallback to `tddCutoverSliceId`) to exempt
|
|
669
|
-
* pre-flip closed slices on `legacyContinuation: true` projects.
|
|
670
|
-
*/
|
|
671
|
-
tddWorktreeCutoverSliceId: string;
|
|
635
|
+
packageVersion?: string | null;
|
|
672
636
|
}
|
|
@@ -87,8 +87,8 @@ function detectStopSignal(rows) {
|
|
|
87
87
|
}
|
|
88
88
|
/**
|
|
89
89
|
* Validate the kebab-case ASCII shape of a forcing-question topic ID.
|
|
90
|
-
*
|
|
91
|
-
*
|
|
90
|
+
* IDs are short, language-neutral identifiers authors can paste into a
|
|
91
|
+
* `[topic:<id>]` tag without typos.
|
|
92
92
|
*/
|
|
93
93
|
const TOPIC_ID_PATTERN = /^[a-z0-9][a-z0-9-]*$/u;
|
|
94
94
|
function isValidTopicId(id) {
|
|
@@ -98,9 +98,9 @@ function isValidTopicId(id) {
|
|
|
98
98
|
* Parse a single checklist row into the list of forcing-question topic
|
|
99
99
|
* descriptors it declares. Returns `null` when the row is not a
|
|
100
100
|
* forcing-questions header. Throws when the header is found but its
|
|
101
|
-
* body does not match the
|
|
102
|
-
*
|
|
103
|
-
*
|
|
101
|
+
* body does not match the `id: topic; id: topic; ...` syntax — authors
|
|
102
|
+
* fix the stage definition rather than silently ship un-coverable
|
|
103
|
+
* topics.
|
|
104
104
|
*
|
|
105
105
|
* Exposed for unit tests that exercise the parser without depending on
|
|
106
106
|
* the live stage schema.
|
|
@@ -125,7 +125,7 @@ export function parseForcingQuestionsRow(row, context = "row") {
|
|
|
125
125
|
for (const segment of segments) {
|
|
126
126
|
const match = /^[`*_]?\s*([A-Za-z0-9][A-Za-z0-9-]*)\s*[`*_]?\s*:\s*(.+?)\s*$/u.exec(segment);
|
|
127
127
|
if (!match) {
|
|
128
|
-
throw new Error(`parseForcingQuestionsRow(${context}): segment "${segment}" does not match required \`id: topic\` syntax.
|
|
128
|
+
throw new Error(`parseForcingQuestionsRow(${context}): segment "${segment}" does not match required \`id: topic\` syntax. Use \`id: topic; id: topic; ...\` form.`);
|
|
129
129
|
}
|
|
130
130
|
const id = (match[1] ?? "").toLowerCase();
|
|
131
131
|
const topic = (match[2] ?? "").replace(/[`*_]+$/u, "").trim();
|
|
@@ -142,9 +142,9 @@ export function parseForcingQuestionsRow(row, context = "row") {
|
|
|
142
142
|
/**
|
|
143
143
|
* Extract forcing-question topics from a stage's checklist.
|
|
144
144
|
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
145
|
+
* Only the `id: topic; id: topic; ...` syntax is accepted. Throws when
|
|
146
|
+
* the syntax is malformed so authors fix the stage definition rather
|
|
147
|
+
* than silently shipping un-coverable topics.
|
|
148
148
|
*
|
|
149
149
|
* Returns empty array when no forcing-questions row is present (caller
|
|
150
150
|
* treats absence as "no forcing requirement" — convergence falls back
|
|
@@ -219,10 +219,9 @@ function lastTwoRowsAllNoDecision(substantiveRows) {
|
|
|
219
219
|
* `skipQuestionsAdvisory` is true (linter treats as non-blocking).
|
|
220
220
|
* - No forcing-questions row in the checklist and ≥1 substantive row.
|
|
221
221
|
*
|
|
222
|
-
*
|
|
223
|
-
* `
|
|
224
|
-
*
|
|
225
|
-
* liteShortCircuit false).
|
|
222
|
+
* `[topic:<id>]` is the sole topic-coverage signal. The `min` and
|
|
223
|
+
* `liteShortCircuit` fields stay for harness compatibility (min is
|
|
224
|
+
* always 0; liteShortCircuit false).
|
|
226
225
|
*/
|
|
227
226
|
export function evaluateQaLogFloor(qaLogBody, track, stage, options = {}) {
|
|
228
227
|
const rows = qaLogBody !== null ? getMarkdownTableRows(qaLogBody) : [];
|
|
@@ -886,12 +885,11 @@ export function extractCanonicalScopeMode(body) {
|
|
|
886
885
|
}
|
|
887
886
|
return null;
|
|
888
887
|
}
|
|
889
|
-
//
|
|
890
|
-
//
|
|
891
|
-
//
|
|
892
|
-
//
|
|
893
|
-
//
|
|
894
|
-
// path (no specialized validator required).
|
|
888
|
+
// Premise challenge is owned solely by brainstorm (`## Premise Check`);
|
|
889
|
+
// scope only records `## Premise Drift` when scope-stage Q&A surfaces
|
|
890
|
+
// new evidence that materially changes the brainstorm answer. The
|
|
891
|
+
// drift section is optional and structural-only via the default
|
|
892
|
+
// `validateSectionBody` path (no specialized validator required).
|
|
895
893
|
export function validateScopeSummary(sectionBody) {
|
|
896
894
|
const meaningfulLines = sectionBody
|
|
897
895
|
.split(/\r?\n/)
|
|
@@ -1147,9 +1145,9 @@ export function validateInteractionEdgeCaseMatrix(sectionBody, context = {}) {
|
|
|
1147
1145
|
};
|
|
1148
1146
|
}
|
|
1149
1147
|
if (isNA) {
|
|
1150
|
-
//
|
|
1151
|
-
//
|
|
1152
|
-
//
|
|
1148
|
+
// `N/A — <reason>` short-circuits both the "must mark yes/no"
|
|
1149
|
+
// rule and the "must reference a deferred item id" rule. The
|
|
1150
|
+
// reason satisfies justification.
|
|
1153
1151
|
const hasReason = INTERACTION_EDGE_CASE_NA_WITH_REASON_PATTERN.test(handledRaw) || response.length > 0;
|
|
1154
1152
|
if (!hasReason) {
|
|
1155
1153
|
return {
|
|
@@ -1228,7 +1226,7 @@ export const DIAGRAM_ARROW_PATTERN = /(?:<--?>|<?==?>|--?>|->>|=>|-\.->|→|⟶|
|
|
|
1228
1226
|
export const DIAGRAM_FAILURE_EDGE_PATTERN = /\b(fail(?:ed|ure)?|error|timeout|fallback|degrad(?:e|ed|ation)|retry|backoff|circuit|unavailable|recover(?:y)?|rescue|mitigat(?:e|ion)|rollback|exception|abort|dead[\s-]?letter|dlq)\b/iu;
|
|
1229
1227
|
export const DIAGRAM_GENERIC_NODE_PATTERN = /\b(service|component|module|system)\s*(?:[A-Z0-9])?\b/iu;
|
|
1230
1228
|
/**
|
|
1231
|
-
*
|
|
1229
|
+
* external-dependency keywords that trigger the
|
|
1232
1230
|
* failure-edge requirement. The architecture diagram is allowed to
|
|
1233
1231
|
* omit failure edges only when ALL of:
|
|
1234
1232
|
* - Failure Mode Table has zero rows.
|
|
@@ -1266,7 +1264,7 @@ export function hasLabeledDiagramArrow(lines) {
|
|
|
1266
1264
|
return lines.some((line) => /\|[^|]+\|/u.test(line) || /:\s*[A-Za-z]/u.test(line));
|
|
1267
1265
|
}
|
|
1268
1266
|
/**
|
|
1269
|
-
*
|
|
1267
|
+
* accepted async edge patterns. Returns true when
|
|
1270
1268
|
* a line carries any of:
|
|
1271
1269
|
*
|
|
1272
1270
|
* - `-.->`, `-->>`, `~~>` (mermaid dotted/messaging arrows)
|
|
@@ -1297,7 +1295,7 @@ export function hasAsyncDiagramEdge(lines) {
|
|
|
1297
1295
|
});
|
|
1298
1296
|
}
|
|
1299
1297
|
/**
|
|
1300
|
-
*
|
|
1298
|
+
* accepted sync edge patterns. Returns true when a
|
|
1301
1299
|
* line carries any of:
|
|
1302
1300
|
*
|
|
1303
1301
|
* - `\bsync\b` text token (label-based)
|
|
@@ -1329,7 +1327,7 @@ export function hasSyncDiagramEdge(lines) {
|
|
|
1329
1327
|
});
|
|
1330
1328
|
}
|
|
1331
1329
|
/**
|
|
1332
|
-
*
|
|
1330
|
+
* exact accepted-pattern list shown in the error
|
|
1333
1331
|
* message when sync/async distinction fails. Keep in sync with
|
|
1334
1332
|
* `hasAsyncDiagramEdge` / `hasSyncDiagramEdge` above.
|
|
1335
1333
|
*/
|
|
@@ -1341,7 +1339,7 @@ export const DIAGRAM_SYNC_ASYNC_ACCEPTED_PATTERNS = [
|
|
|
1341
1339
|
"Cell-prefix labels: `sync:` / `async:` (e.g. `A -->|sync: persist| B`)"
|
|
1342
1340
|
];
|
|
1343
1341
|
/**
|
|
1344
|
-
*
|
|
1342
|
+
* Architecture Diagram structural check.
|
|
1345
1343
|
*
|
|
1346
1344
|
* Promoted out of `validateSectionBody` so it can take a `sections`
|
|
1347
1345
|
* map and conditionally enforce the failure-edge rule based on
|
|
@@ -1394,7 +1392,7 @@ export function validateArchitectureDiagram(sectionBody, context = {}) {
|
|
|
1394
1392
|
};
|
|
1395
1393
|
}
|
|
1396
1394
|
/**
|
|
1397
|
-
*
|
|
1395
|
+
* decide whether the failure-edge enforcement
|
|
1398
1396
|
* should fire for the given Architecture Diagram body. Returns
|
|
1399
1397
|
* `false` (skip the rule) when BOTH:
|
|
1400
1398
|
* - The artifact's `## Failure Mode Table` (if present) has zero
|
|
@@ -1799,7 +1797,7 @@ export function parseLearningsSection(sectionBody) {
|
|
|
1799
1797
|
};
|
|
1800
1798
|
}
|
|
1801
1799
|
/**
|
|
1802
|
-
*
|
|
1800
|
+
* file-path / reference detector for the
|
|
1803
1801
|
* `investigation_path_first_missing` advisory rule.
|
|
1804
1802
|
*
|
|
1805
1803
|
* The detector is intentionally permissive: it only needs to recognize
|
|
@@ -1914,7 +1912,7 @@ export function checkInvestigationTrace(sectionBody) {
|
|
|
1914
1912
|
};
|
|
1915
1913
|
}
|
|
1916
1914
|
/**
|
|
1917
|
-
*
|
|
1915
|
+
* advisory rule wired into the brainstorm / scope /
|
|
1918
1916
|
* design / tdd / plan / review linters.
|
|
1919
1917
|
*
|
|
1920
1918
|
* Behavior contract:
|
|
@@ -2004,13 +2002,8 @@ export function extractRequirementIdsFromMarkdown(text) {
|
|
|
2004
2002
|
const ids = text.match(/\bR\d+\b/gu) ?? [];
|
|
2005
2003
|
return [...new Set(ids)];
|
|
2006
2004
|
}
|
|
2007
|
-
//
|
|
2008
|
-
//
|
|
2009
|
-
// stable D-XX IDs.
|
|
2010
|
-
// `lockedDecisionHash` was removed in Wave 22 (v4.0.0) along with the
|
|
2011
|
-
// `Locked Decisions Hash Integrity` linter rule. Decision identity now
|
|
2012
|
-
// relies on stable D-XX IDs which the agent can edit safely without
|
|
2013
|
-
// recomputing content hashes.
|
|
2005
|
+
// Cross-stage decision traceability uses stable D-XX IDs which the
|
|
2006
|
+
// agent can edit safely without recomputing content hashes.
|
|
2014
2007
|
export function collectPatternHits(text, patterns) {
|
|
2015
2008
|
const hits = [];
|
|
2016
2009
|
for (const pattern of patterns) {
|
|
@@ -134,7 +134,7 @@ export async function lintSpecStage(ctx) {
|
|
|
134
134
|
findings.push({
|
|
135
135
|
section: "spec_acs_not_sliceable",
|
|
136
136
|
required: false,
|
|
137
|
-
rule: "Acceptance criteria should declare `parallelSafe` and `touchSurface` per row
|
|
137
|
+
rule: "Acceptance criteria should declare `parallelSafe` and `touchSurface` per row so plan/TDD can schedule slices safely.",
|
|
138
138
|
found: hasParallel && hasTouch,
|
|
139
139
|
details: hasParallel && hasTouch
|
|
140
140
|
? "Acceptance Criteria mentions parallelSafe and touchSurface."
|