cclaw-cli 0.15.1 → 0.21.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.
Files changed (42) hide show
  1. package/dist/artifact-linter.js +154 -0
  2. package/dist/cli.js +2 -1
  3. package/dist/constants.d.ts +2 -2
  4. package/dist/constants.js +4 -3
  5. package/dist/content/compound-command.d.ts +2 -0
  6. package/dist/content/compound-command.js +72 -0
  7. package/dist/content/contracts.js +1 -1
  8. package/dist/content/doctor-references.js +7 -6
  9. package/dist/content/feature-command.js +54 -51
  10. package/dist/content/harnesses-doc.js +5 -3
  11. package/dist/content/hooks.js +2 -2
  12. package/dist/content/ideate-command.d.ts +2 -0
  13. package/dist/content/ideate-command.js +73 -0
  14. package/dist/content/learnings.d.ts +1 -1
  15. package/dist/content/learnings.js +22 -5
  16. package/dist/content/meta-skill.js +6 -3
  17. package/dist/content/next-command.js +5 -5
  18. package/dist/content/observe.js +3 -2
  19. package/dist/content/ops-command.js +4 -4
  20. package/dist/content/protocols.js +27 -38
  21. package/dist/content/retro-command.js +2 -1
  22. package/dist/content/rewind-command.d.ts +0 -1
  23. package/dist/content/rewind-command.js +19 -33
  24. package/dist/content/skills.js +14 -8
  25. package/dist/content/stage-schema.js +3 -38
  26. package/dist/content/stages/plan.js +16 -5
  27. package/dist/content/stages/review.js +20 -0
  28. package/dist/content/stages/scope.js +9 -3
  29. package/dist/content/stages/ship.js +1 -0
  30. package/dist/content/stages/tdd.js +5 -4
  31. package/dist/content/templates.js +105 -9
  32. package/dist/content/utility-skills.d.ts +3 -1
  33. package/dist/content/utility-skills.js +91 -1
  34. package/dist/delegation.d.ts +33 -3
  35. package/dist/delegation.js +56 -3
  36. package/dist/doctor.js +269 -88
  37. package/dist/feature-system.d.ts +22 -5
  38. package/dist/feature-system.js +267 -126
  39. package/dist/harness-adapters.js +17 -1
  40. package/dist/install.js +10 -8
  41. package/dist/policy.js +13 -4
  42. package/package.json +1 -1
@@ -168,6 +168,26 @@ export const REVIEW = {
168
168
  ],
169
169
  stopGate: true
170
170
  },
171
+ {
172
+ title: "Specialist Lens: Data & Migration Safety",
173
+ evaluationPoints: [
174
+ "Schema/data migrations are reversible and include backfill/rollback strategy",
175
+ "Idempotency expectations are explicit for retryable flows",
176
+ "Data-loss scenarios (truncate/overwrite/drop) are guarded by checks or dry-runs",
177
+ "Boundary contracts (API/schema/event payload) maintain backward compatibility or are versioned"
178
+ ],
179
+ stopGate: false
180
+ },
181
+ {
182
+ title: "Specialist Lens: Developer Experience",
183
+ evaluationPoints: [
184
+ "New behavior includes discoverable docs/usage notes where needed",
185
+ "Error messages are actionable for on-call and local debugging",
186
+ "Default configuration remains safe and unsurprising",
187
+ "Change footprint stays minimal and avoids hidden coupling"
188
+ ],
189
+ stopGate: false
190
+ },
171
191
  {
172
192
  title: "Meta-Review: Verify the Verification",
173
193
  evaluationPoints: [
@@ -50,6 +50,7 @@ export const SCOPE = {
50
50
  "Run mode-specific analysis that matches the selected scope mode.",
51
51
  "Walk through scope review sections one at a time.",
52
52
  "Write explicit scope contract, discretion areas, and deferred items.",
53
+ "Freeze non-negotiable boundaries as stable Locked Decisions (D-XX IDs).",
53
54
  "Produce scope summary plus completion dashboard (checklist findings, number of resolved decisions, unresolved items or `None`)."
54
55
  ],
55
56
  requiredGates: [
@@ -65,6 +66,7 @@ export const SCOPE = {
65
66
  "In-scope and out-of-scope lists are explicit.",
66
67
  "Discretion areas are explicit (or marked as `None`).",
67
68
  "Selected mode and rationale are documented.",
69
+ "Locked Decisions section lists stable D-XX IDs for non-negotiable boundaries.",
68
70
  "Premise challenge findings documented.",
69
71
  "Deferred items list with one-line rationale for each.",
70
72
  "Completion dashboard lists checklist findings, decision count, and unresolved items (or `None`)."
@@ -90,6 +92,7 @@ export const SCOPE = {
90
92
  "discretion areas recorded explicitly",
91
93
  "required gates marked satisfied",
92
94
  "deferred list recorded explicitly",
95
+ "locked decisions captured with stable D-XX IDs",
93
96
  "completion dashboard produced",
94
97
  "scope summary produced"
95
98
  ],
@@ -100,7 +103,8 @@ export const SCOPE = {
100
103
  "Sycophantic agreement without evidence-based pushback",
101
104
  "Hedged recommendations that avoid taking a position",
102
105
  "Batching multiple scope issues into one question",
103
- "Re-arguing for smaller scope after user rejects reduction"
106
+ "Re-arguing for smaller scope after user rejects reduction",
107
+ "Using scope-reduction placeholders (`v1`, `for now`, `we can do later`) instead of explicit user-approved boundaries"
104
108
  ],
105
109
  redFlags: [
106
110
  "No selected mode in artifact",
@@ -109,9 +113,10 @@ export const SCOPE = {
109
113
  "No deferred/not-in-scope section",
110
114
  "No user approval marker",
111
115
  "Premise challenge missing or superficial",
112
- "No implementation alternatives evaluated"
116
+ "No implementation alternatives evaluated",
117
+ "Missing Locked Decisions section or decisions without D-XX IDs"
113
118
  ],
114
- policyNeedles: ["Scope mode", "In Scope", "Out of Scope", "Discretion Areas", "NOT in scope", "Premise Challenge"],
119
+ policyNeedles: ["Scope mode", "In Scope", "Out of Scope", "Discretion Areas", "NOT in scope", "Premise Challenge", "Locked Decisions"],
115
120
  artifactFile: "02-scope.md",
116
121
  next: "design",
117
122
  reviewSections: [
@@ -173,6 +178,7 @@ export const SCOPE = {
173
178
  { section: "Prime Directives", required: true, validationRule: "For each scoped capability: named failure modes, explicit error surface, four data-flow paths, interaction edge cases, observability expectations, and deferred-item handling." },
174
179
  { section: "Premise Challenge", required: true, validationRule: "Must contain explicit answers to: right problem? direct path? what if nothing?" },
175
180
  { section: "Requirements", required: true, 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`." },
181
+ { section: "Locked Decisions (D-XX)", required: false, validationRule: "List of stable locked decisions with IDs D-01, D-02... Each ID appears once, includes rationale, and is intended for downstream cross-stage traceability." },
176
182
  { section: "Implementation Alternatives", required: true, validationRule: "2-3 options with Name, Summary, Effort, Risk, Pros, Cons, and Reuses. Must include minimal viable and ideal architecture options." },
177
183
  { section: "Scope Mode", required: true, validationRule: "Must state selected mode and rationale with default heuristic justification." },
178
184
  { section: "Mode-Specific Analysis", required: true, validationRule: "Must document the analysis matching the selected scope mode: EXPAND (10x and delight opportunities), SELECTIVE (hold-scope baseline then cherry-picked expansions), HOLD (minimum-change-set hardening), REDUCE (ruthless cuts and follow-up split)." },
@@ -26,6 +26,7 @@ export const SHIP = {
26
26
  "Re-run tests on merged result — if merging locally, run the full test suite AFTER the merge, not just before. Post-merge failures are common.",
27
27
  "Generate release notes — summarize what changed, why, and what it affects. Reference spec criteria. Include: breaking changes, new dependencies, migration steps if any.",
28
28
  "Write rollback plan — trigger conditions (what tells you it is broken), rollback steps (exact commands/git operations), and verification (how to confirm rollback worked).",
29
+ "Load utility skills — `verification-before-completion` for fresh evidence and `finishing-a-development-branch` for finalization workflow.",
29
30
  "Monitoring checklist — what should be watched after deploy? Error rates, latency, key business metrics. If no monitoring exists, flag it as a risk.",
30
31
  "Select finalization mode — exactly ONE enum: (A) FINALIZE_MERGE_LOCAL, (B) FINALIZE_OPEN_PR, (C) FINALIZE_KEEP_BRANCH, (D) FINALIZE_DISCARD_BRANCH. For discard: list what will be deleted, require typed confirmation.",
31
32
  "Execute finalization — perform the selected action. For merge: verify clean merge. For PR: include structured body (summary, test plan, rollback). For discard: verify deletion.",
@@ -22,9 +22,9 @@ export const TDD = {
22
22
  checklist: [
23
23
  "Select plan slice — pick one task from the plan. Do not batch multiple tasks.",
24
24
  "Map to acceptance criterion — identify the specific spec criterion this test proves.",
25
- "RED: Write behavior-focused testtest the expected behavior, not implementation details. Tests MUST fail.",
25
+ "Dispatch mandatory `test-author` subagent in `TEST_RED_ONLY` mode produce failing behavior tests and RED evidence only (no production edits).",
26
26
  "RED: Capture failure output — copy the exact failure output as RED evidence. Record in artifact.",
27
- "GREEN: Minimal implementation write the smallest code change that makes the RED tests pass. No extra features.",
27
+ "Dispatch `test-author` subagent in `BUILD_GREEN_REFACTOR` mode minimal implementation + full-suite GREEN + refactor notes.",
28
28
  "GREEN: Run full suite — execute ALL tests, not just the ones you wrote. The full suite must be GREEN.",
29
29
  "GREEN: Verify no regressions — if any existing test breaks, fix the regression before proceeding.",
30
30
  "REFACTOR: Improve code quality — without changing behavior. Document what you changed and why.",
@@ -34,6 +34,7 @@ export const TDD = {
34
34
  ],
35
35
  interactionProtocol: [
36
36
  "Pick one planned slice at a time.",
37
+ "Controller owns orchestration; execution runs through the mandatory `test-author` delegation for RED then GREEN/REFACTOR modes.",
37
38
  "Write behavior-focused tests before changing implementation (RED).",
38
39
  "Capture and store failing output as RED evidence.",
39
40
  "Apply minimal change to satisfy RED tests (GREEN).",
@@ -44,9 +45,9 @@ export const TDD = {
44
45
  ],
45
46
  process: [
46
47
  "Select slice and map to acceptance criterion.",
47
- "Write test(s) that fail for expected reason (RED).",
48
+ "Dispatch `test-author` in TEST_RED_ONLY mode and produce failing test(s) for expected reason (RED).",
48
49
  "Run tests and capture failure output.",
49
- "Implement smallest change needed for GREEN.",
50
+ "Dispatch `test-author` in BUILD_GREEN_REFACTOR mode and implement smallest change needed for GREEN.",
50
51
  "Run full tests and build checks.",
51
52
  "Perform refactor pass preserving behavior.",
52
53
  "Record RED, GREEN, and REFACTOR evidence in artifact.",
@@ -1,7 +1,16 @@
1
1
  import { COMMAND_FILE_ORDER } from "../constants.js";
2
2
  import { orderedStageSchemas } from "./stage-schema.js";
3
3
  export const ARTIFACT_TEMPLATES = {
4
- "01-brainstorm.md": `# Brainstorm Artifact
4
+ "01-brainstorm.md": `---
5
+ stage: brainstorm
6
+ schema_version: 1
7
+ version: 0.18.0
8
+ feature: <feature-id>
9
+ locked_decisions: []
10
+ inputs_hash: sha256:pending
11
+ ---
12
+
13
+ # Brainstorm Artifact
5
14
 
6
15
  ## Context
7
16
  - **Project state:**
@@ -37,7 +46,16 @@ export const ARTIFACT_TEMPLATES = {
37
46
  - **Assumptions:**
38
47
  - **Open questions (or "None"):**
39
48
  `,
40
- "02-scope.md": `# Scope Artifact
49
+ "02-scope.md": `---
50
+ stage: scope
51
+ schema_version: 1
52
+ version: 0.18.0
53
+ feature: <feature-id>
54
+ locked_decisions: []
55
+ inputs_hash: sha256:pending
56
+ ---
57
+
58
+ # Scope Artifact
41
59
 
42
60
  ## Prime Directives
43
61
  - Zero silent failures:
@@ -94,6 +112,11 @@ export const ARTIFACT_TEMPLATES = {
94
112
  > is later dropped, keep the row and mark Priority \`DROPPED\`; if a new one is
95
113
  > added mid-flow, append with the next free R-number — do NOT reuse numbers.
96
114
 
115
+ ## Locked Decisions (D-XX)
116
+ | Decision ID | Decision | Why locked now | Downstream impact |
117
+ |---|---|---|---|
118
+ | D-01 | | | |
119
+
97
120
  ## In Scope / Out of Scope
98
121
 
99
122
  ### In Scope
@@ -126,7 +149,16 @@ export const ARTIFACT_TEMPLATES = {
126
149
  - Deferred:
127
150
  - Explicitly excluded:
128
151
  `,
129
- "03-design.md": `# Design Artifact
152
+ "03-design.md": `---
153
+ stage: design
154
+ schema_version: 1
155
+ version: 0.18.0
156
+ feature: <feature-id>
157
+ locked_decisions: []
158
+ inputs_hash: sha256:pending
159
+ ---
160
+
161
+ # Design Artifact
130
162
 
131
163
  ## Codebase Investigation
132
164
  | File | Current responsibility | Patterns discovered |
@@ -210,7 +242,16 @@ export const ARTIFACT_TEMPLATES = {
210
242
 
211
243
  **Decisions made:** 0 | **Unresolved:** 0
212
244
  `,
213
- "04-spec.md": `# Specification Artifact
245
+ "04-spec.md": `---
246
+ stage: spec
247
+ schema_version: 1
248
+ version: 0.18.0
249
+ feature: <feature-id>
250
+ locked_decisions: []
251
+ inputs_hash: sha256:pending
252
+ ---
253
+
254
+ # Specification Artifact
214
255
 
215
256
  ## Acceptance Criteria
216
257
  | ID | Requirement Ref (R#) | Criterion (observable/measurable/falsifiable) | Design Decision Ref |
@@ -254,7 +295,16 @@ export const ARTIFACT_TEMPLATES = {
254
295
  - Approved by:
255
296
  - Date:
256
297
  `,
257
- "05-plan.md": `# Plan Artifact
298
+ "05-plan.md": `---
299
+ stage: plan
300
+ schema_version: 1
301
+ version: 0.18.0
302
+ feature: <feature-id>
303
+ locked_decisions: []
304
+ inputs_hash: sha256:pending
305
+ ---
306
+
307
+ # Plan Artifact
258
308
 
259
309
  ## Dependency Graph
260
310
  -
@@ -282,6 +332,7 @@ Execution rule: complete and verify each wave before starting the next wave.
282
332
  **Rules (apply before writing rows):**
283
333
  - Every task fits the **2-5 minute budget**. If \`[~Nm]\` is >5, split the task.
284
334
  - **No placeholders.** Forbidden tokens anywhere in this table: \`TODO\`, \`TBD\`, \`FIXME\`, \`<fill-in>\`, \`<your-*-here>\`, \`xxx\`, bare ellipsis. Every file path, test, and verification command must be copy-pasteable as written.
335
+ - **No silent scope reduction.** Forbidden phrasing when locked decisions exist: \`v1\`, \`for now\`, \`later\`, \`temporary\`, \`placeholder\`, \`mock for now\`, \`hardcoded for now\`, \`will improve later\`.
285
336
  - If an estimate is genuinely uncertain (new library, unfamiliar subsystem), add a **spike task in wave 0** to de-risk — do NOT hide the uncertainty inside a large estimate.
286
337
 
287
338
  | Task ID | Description | Acceptance criterion | Verification command | Effort (S/M/L) | Minutes |
@@ -293,6 +344,11 @@ Execution rule: complete and verify each wave before starting the next wave.
293
344
  |---|---|
294
345
  | AC-1 | T-1 |
295
346
 
347
+ ## Locked Decision Coverage
348
+ | Decision ID | Source section | Plan tasks implementing decision | Status |
349
+ |---|---|---|---|
350
+ | D-01 | 02-scope.md > Locked Decisions | T-1 | covered |
351
+
296
352
  ## Risk Assessment
297
353
  | Task/Wave | Risk | Likelihood | Impact | Mitigation |
298
354
  |---|---|---|---|---|
@@ -307,11 +363,24 @@ Execution rule: complete and verify each wave before starting the next wave.
307
363
  - Scanned tokens: \`TODO\`, \`TBD\`, \`FIXME\`, \`<fill-in>\`, \`<your-*-here>\`, \`xxx\`, bare ellipsis in task rows.
308
364
  - Hits: 0 (required for WAIT_FOR_CONFIRM to resolve).
309
365
 
366
+ ## No Scope Reduction Language Scan
367
+ - Scanned phrases: \`v1\`, \`for now\`, \`later\`, \`temporary\`, \`placeholder\`, \`mock for now\`, \`hardcoded for now\`, \`will improve later\`.
368
+ - Hits: 0 (required when Locked Decisions section is non-empty).
369
+
310
370
  ## WAIT_FOR_CONFIRM
311
371
  - Status: pending
312
372
  - Confirmed by:
313
373
  `,
314
- "06-tdd.md": `# TDD Artifact
374
+ "06-tdd.md": `---
375
+ stage: tdd
376
+ schema_version: 1
377
+ version: 0.18.0
378
+ feature: <feature-id>
379
+ locked_decisions: []
380
+ inputs_hash: sha256:pending
381
+ ---
382
+
383
+ # TDD Artifact
315
384
 
316
385
  ## RED Evidence
317
386
  | Slice | Test name | Command | Failure output summary |
@@ -366,7 +435,16 @@ Execution rule: complete and verify each wave before starting the next wave.
366
435
  |---|---|---|---|---|
367
436
  | S-1 | | | | |
368
437
  `,
369
- "07-review.md": `# Review Artifact
438
+ "07-review.md": `---
439
+ stage: review
440
+ schema_version: 1
441
+ version: 0.18.0
442
+ feature: <feature-id>
443
+ locked_decisions: []
444
+ inputs_hash: sha256:pending
445
+ ---
446
+
447
+ # Review Artifact
370
448
 
371
449
  ## Layer 1 Verdict
372
450
  | Criterion | Verdict | Evidence |
@@ -444,7 +522,16 @@ Execution rule: complete and verify each wave before starting the next wave.
444
522
  }
445
523
  }
446
524
  `,
447
- "08-ship.md": `# Ship Artifact
525
+ "08-ship.md": `---
526
+ stage: ship
527
+ schema_version: 1
528
+ version: 0.18.0
529
+ feature: <feature-id>
530
+ locked_decisions: []
531
+ inputs_hash: sha256:pending
532
+ ---
533
+
534
+ # Ship Artifact
448
535
 
449
536
  ## Preflight Results
450
537
  - Review verdict:
@@ -485,7 +572,16 @@ Execution rule: complete and verify each wave before starting the next wave.
485
572
  - Retro artifact path: \`.cclaw/artifacts/09-retro.md\`
486
573
  - Archive remains blocked until retro gate is complete.
487
574
  `,
488
- "09-retro.md": `# Retro Artifact
575
+ "09-retro.md": `---
576
+ stage: retro
577
+ schema_version: 1
578
+ version: 0.18.0
579
+ feature: <feature-id>
580
+ locked_decisions: []
581
+ inputs_hash: sha256:pending
582
+ ---
583
+
584
+ # Retro Artifact
489
585
 
490
586
  ## Run Summary
491
587
  - Flow track:
@@ -10,6 +10,8 @@ export declare function ciCdSkill(): string;
10
10
  export declare function docsSkill(): string;
11
11
  export declare function executingPlansSkill(): string;
12
12
  export declare function contextEngineeringSkill(): string;
13
+ export declare function verificationBeforeCompletionSkill(): string;
14
+ export declare function finishingDevelopmentBranchSkill(): string;
13
15
  export declare function sourceDrivenDevelopmentSkill(): string;
14
16
  export declare function frontendAccessibilitySkill(): string;
15
17
  export declare function landscapeCheckSkill(): string;
@@ -44,5 +46,5 @@ export declare const LANGUAGE_RULE_PACK_GENERATORS: Record<string, () => string>
44
46
  * clean them up after the move to `.cclaw/rules/lang/`.
45
47
  */
46
48
  export declare const LEGACY_LANGUAGE_RULE_PACK_FOLDERS: readonly ["language-typescript", "language-python", "language-go"];
47
- export declare const UTILITY_SKILL_FOLDERS: readonly ["security", "debugging", "performance", "ci-cd", "docs", "executing-plans", "context-engineering", "source-driven-development", "frontend-accessibility", "landscape-check", "adversarial-review", "security-audit", "knowledge-curation", "retrospective", "document-review"];
49
+ export declare const UTILITY_SKILL_FOLDERS: readonly ["security", "debugging", "performance", "ci-cd", "docs", "executing-plans", "verification-before-completion", "finishing-a-development-branch", "context-engineering", "source-driven-development", "frontend-accessibility", "landscape-check", "adversarial-review", "security-audit", "knowledge-curation", "retrospective", "document-review"];
48
50
  export declare const UTILITY_SKILL_MAP: Record<string, () => string>;
@@ -594,6 +594,92 @@ Modes are stored in \`.cclaw/contexts/\`:
594
594
  - Shipping decisions based on stale pre-compaction context.
595
595
  `;
596
596
  }
597
+ export function verificationBeforeCompletionSkill() {
598
+ return `---
599
+ name: verification-before-completion
600
+ description: "Final verification discipline before stage closeout or ship. Use when preparing a completion claim."
601
+ ---
602
+
603
+ # Verification Before Completion
604
+
605
+ ## Announce at start
606
+
607
+ "Using verification-before-completion to validate fresh evidence before completion."
608
+
609
+ ## HARD-GATE
610
+
611
+ Do not claim completion from memory. Every pass claim requires fresh, in-turn evidence.
612
+
613
+ ## Protocol
614
+
615
+ 1. Identify changed scope (files, modules, user-facing behaviors).
616
+ 2. Run the smallest command set that still proves the scope:
617
+ - tests for changed area
618
+ - typecheck/build/lint if the stack requires it
619
+ 3. Capture exact command + pass/fail output in the artifact.
620
+ 4. If this is a bug fix, include RED -> GREEN regression evidence.
621
+ 5. If any check fails, stop completion and return to fix loop.
622
+
623
+ ## Completion claim checklist
624
+
625
+ - [ ] Commands were run in this turn (not reused from earlier output).
626
+ - [ ] Output corresponds to the actual changed scope.
627
+ - [ ] Failures (if any) are resolved or explicitly escalated.
628
+ - [ ] Artifact includes evidence references.
629
+ - [ ] Completion status reflects evidence (DONE / DONE_WITH_CONCERNS / BLOCKED).
630
+
631
+ ## Anti-patterns
632
+
633
+ - "Tests passed earlier today" without rerunning.
634
+ - Reporting only "PASS" without command context.
635
+ - Running unrelated checks while skipping changed scope checks.
636
+ - Marking DONE while blockers still fail.
637
+ `;
638
+ }
639
+ export function finishingDevelopmentBranchSkill() {
640
+ return `---
641
+ name: finishing-a-development-branch
642
+ description: "Finalize implementation branch after review: verify, choose integration mode, execute safely, and clean up."
643
+ ---
644
+
645
+ # Finishing a Development Branch
646
+
647
+ ## Announce at start
648
+
649
+ "Using finishing-a-development-branch to complete this branch safely."
650
+
651
+ ## HARD-GATE
652
+
653
+ Do not merge, open PR, or discard branch until verification and rollback notes are explicit.
654
+
655
+ ## Protocol
656
+
657
+ 1. Verify readiness:
658
+ - review verdict is APPROVED or APPROVED_WITH_CONCERNS
659
+ - verification-before-completion checklist is satisfied
660
+ 2. Choose one finalization mode:
661
+ - FINALIZE_MERGE_LOCAL
662
+ - FINALIZE_OPEN_PR
663
+ - FINALIZE_KEEP_BRANCH
664
+ - FINALIZE_DISCARD_BRANCH
665
+ 3. Execute only the chosen mode and record exact result.
666
+ 4. If merge or discard happened in a feature worktree, clean the worktree.
667
+ 5. Update ship artifact with release notes, rollback, and finalization evidence.
668
+
669
+ ## Rollback minimum
670
+
671
+ - Trigger: what tells us release is wrong.
672
+ - Steps: exact revert/reset/rollback commands.
673
+ - Verification: how we confirm rollback worked.
674
+
675
+ ## Anti-patterns
676
+
677
+ - Multiple finalization modes in one run.
678
+ - Merge without rollback section.
679
+ - PR without test/verification summary.
680
+ - Discarding branch without explicit user confirmation.
681
+ `;
682
+ }
597
683
  export function sourceDrivenDevelopmentSkill() {
598
684
  return `---
599
685
  name: source-driven-development
@@ -1271,7 +1357,7 @@ For each lens, write either a knowledge entry **or** the explicit string
1271
1357
  ## Output protocol
1272
1358
 
1273
1359
  For every harvested insight, append one strict-schema JSON line to
1274
- \`.cclaw/knowledge.jsonl\` (fields: \`type, trigger, action, confidence, domain, stage, created, project\`).
1360
+ \`.cclaw/knowledge.jsonl\` (fields: \`type, trigger, action, confidence, domain, stage, origin_stage, origin_feature, frequency, universality, maturity, created, first_seen_ts, last_seen_ts, project\`).
1275
1361
  See the \`learnings\` skill for the canonical shape. Choose \`type\`:
1276
1362
 
1277
1363
  - \`compound\` for process/speed accelerators.
@@ -1524,6 +1610,8 @@ export const UTILITY_SKILL_FOLDERS = [
1524
1610
  "ci-cd",
1525
1611
  "docs",
1526
1612
  "executing-plans",
1613
+ "verification-before-completion",
1614
+ "finishing-a-development-branch",
1527
1615
  "context-engineering",
1528
1616
  "source-driven-development",
1529
1617
  "frontend-accessibility",
@@ -1541,6 +1629,8 @@ export const UTILITY_SKILL_MAP = {
1541
1629
  "ci-cd": ciCdSkill,
1542
1630
  docs: docsSkill,
1543
1631
  "executing-plans": executingPlansSkill,
1632
+ "verification-before-completion": verificationBeforeCompletionSkill,
1633
+ "finishing-a-development-branch": finishingDevelopmentBranchSkill,
1544
1634
  "context-engineering": contextEngineeringSkill,
1545
1635
  "source-driven-development": sourceDrivenDevelopmentSkill,
1546
1636
  "frontend-accessibility": frontendAccessibilitySkill,
@@ -1,12 +1,34 @@
1
1
  import type { FlowStage } from "./types.js";
2
+ export type DelegationMode = "mandatory" | "proactive" | "conditional";
3
+ export type DelegationStatus = "scheduled" | "completed" | "failed" | "waived";
4
+ export interface DelegationTokenUsage {
5
+ input: number;
6
+ output: number;
7
+ model: string;
8
+ }
2
9
  export type DelegationEntry = {
3
10
  stage: string;
4
11
  agent: string;
5
- mode: "mandatory" | "proactive" | "conditional";
6
- status: "scheduled" | "completed" | "failed" | "waived";
12
+ mode: DelegationMode;
13
+ status: DelegationStatus;
14
+ /**
15
+ * Span identifier for this delegation unit. Multiple status transitions for
16
+ * the same delegated unit should reuse the same spanId.
17
+ */
18
+ spanId?: string;
19
+ /** Parent span id when this delegation was spawned from another span. */
20
+ parentSpanId?: string;
21
+ /** ISO timestamp when the delegation span started. */
22
+ startTs?: string;
23
+ /** ISO timestamp when the delegation span ended (for terminal statuses). */
24
+ endTs?: string;
25
+ /**
26
+ * Legacy timestamp used by historical ledgers. New writers set both `ts` and
27
+ * `startTs` for backward compatibility.
28
+ */
7
29
  taskId?: string;
8
30
  waiverReason?: string;
9
- ts: string;
31
+ ts?: string;
10
32
  /**
11
33
  * Run id the entry belongs to. Older ledgers written before 0.5.17 may omit this;
12
34
  * consumers treat missing runId as unscoped (conservatively excluded from current-run checks).
@@ -17,6 +39,14 @@ export type DelegationEntry = {
17
39
  * Recorded for audit so reviewers can see why the second pass was required.
18
40
  */
19
41
  conditionTrigger?: string;
42
+ /** Optional token usage captured from the delegated run. */
43
+ tokens?: DelegationTokenUsage;
44
+ /** Number of retries attempted for this span. */
45
+ retryCount?: number;
46
+ /** Optional references to evidence anchors in artifacts. */
47
+ evidenceRefs?: string[];
48
+ /** Schema version marker for span-compatible delegation logs. */
49
+ schemaVersion?: 1;
20
50
  };
21
51
  export type DelegationLedger = {
22
52
  runId: string;
@@ -12,6 +12,20 @@ function delegationLogPath(projectRoot) {
12
12
  function delegationLockPath(projectRoot) {
13
13
  return path.join(projectRoot, RUNTIME_ROOT, "state", ".delegation.lock");
14
14
  }
15
+ function createSpanId() {
16
+ return `dspan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
17
+ }
18
+ function isDelegationTokenUsage(value) {
19
+ if (!value || typeof value !== "object" || Array.isArray(value))
20
+ return false;
21
+ const o = value;
22
+ return (typeof o.input === "number" &&
23
+ Number.isFinite(o.input) &&
24
+ typeof o.output === "number" &&
25
+ Number.isFinite(o.output) &&
26
+ typeof o.model === "string" &&
27
+ o.model.trim().length > 0);
28
+ }
15
29
  function isDelegationEntry(value) {
16
30
  if (!value || typeof value !== "object" || Array.isArray(value))
17
31
  return false;
@@ -21,15 +35,30 @@ function isDelegationEntry(value) {
21
35
  o.status === "completed" ||
22
36
  o.status === "failed" ||
23
37
  o.status === "waived";
38
+ const timestampOk = typeof o.ts === "string" ||
39
+ typeof o.startTs === "string";
40
+ const retryOk = o.retryCount === undefined ||
41
+ (typeof o.retryCount === "number" &&
42
+ Number.isFinite(o.retryCount) &&
43
+ Number.isInteger(o.retryCount) &&
44
+ o.retryCount >= 0);
24
45
  return (typeof o.stage === "string" &&
25
46
  typeof o.agent === "string" &&
26
47
  modeOk &&
27
48
  statusOk &&
28
- typeof o.ts === "string" &&
49
+ timestampOk &&
50
+ (o.spanId === undefined || typeof o.spanId === "string") &&
51
+ (o.parentSpanId === undefined || typeof o.parentSpanId === "string") &&
52
+ (o.startTs === undefined || typeof o.startTs === "string") &&
53
+ (o.endTs === undefined || typeof o.endTs === "string") &&
29
54
  (o.taskId === undefined || typeof o.taskId === "string") &&
30
55
  (o.waiverReason === undefined || typeof o.waiverReason === "string") &&
31
56
  (o.runId === undefined || typeof o.runId === "string") &&
32
- (o.conditionTrigger === undefined || typeof o.conditionTrigger === "string"));
57
+ (o.conditionTrigger === undefined || typeof o.conditionTrigger === "string") &&
58
+ (o.tokens === undefined || isDelegationTokenUsage(o.tokens)) &&
59
+ retryOk &&
60
+ (o.evidenceRefs === undefined || (Array.isArray(o.evidenceRefs) && o.evidenceRefs.every((item) => typeof item === "string"))) &&
61
+ (o.schemaVersion === undefined || o.schemaVersion === 1));
33
62
  }
34
63
  function parseLedger(raw, runId) {
35
64
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
@@ -41,7 +70,18 @@ function parseLedger(raw, runId) {
41
70
  if (Array.isArray(entriesRaw)) {
42
71
  for (const item of entriesRaw) {
43
72
  if (isDelegationEntry(item)) {
44
- entries.push(item);
73
+ const ts = item.startTs ?? item.ts ?? new Date().toISOString();
74
+ entries.push({
75
+ ...item,
76
+ spanId: item.spanId ?? createSpanId(),
77
+ startTs: ts,
78
+ ts,
79
+ retryCount: typeof item.retryCount === "number" && Number.isInteger(item.retryCount) && item.retryCount >= 0
80
+ ? item.retryCount
81
+ : 0,
82
+ evidenceRefs: Array.isArray(item.evidenceRefs) ? item.evidenceRefs : [],
83
+ schemaVersion: 1
84
+ });
45
85
  }
46
86
  }
47
87
  }
@@ -67,7 +107,20 @@ export async function appendDelegation(projectRoot, entry) {
67
107
  await withDirectoryLock(delegationLockPath(projectRoot), async () => {
68
108
  const filePath = delegationLogPath(projectRoot);
69
109
  const prior = await readDelegationLedger(projectRoot);
110
+ const startTs = entry.startTs ?? entry.ts ?? new Date().toISOString();
70
111
  const stamped = { ...entry, runId: entry.runId ?? activeRunId };
112
+ stamped.spanId = entry.spanId ?? createSpanId();
113
+ stamped.startTs = startTs;
114
+ stamped.ts = startTs;
115
+ stamped.schemaVersion = 1;
116
+ if (stamped.retryCount === undefined ||
117
+ !Number.isInteger(stamped.retryCount) ||
118
+ stamped.retryCount < 0) {
119
+ stamped.retryCount = 0;
120
+ }
121
+ if (!Array.isArray(stamped.evidenceRefs)) {
122
+ stamped.evidenceRefs = [];
123
+ }
71
124
  const ledger = {
72
125
  runId: activeRunId,
73
126
  entries: [...prior.entries, stamped]