@gobing-ai/spur 0.3.41 → 0.3.43

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 (185) hide show
  1. package/.claude-plugin/marketplace.json +15 -0
  2. package/README.md +15 -1
  3. package/config/templates/AGENTS.md +5 -3
  4. package/config/workflows/task-pipeline.yaml +113 -12
  5. package/package.json +15 -12
  6. package/plugins/README.md +655 -0
  7. package/plugins/sp/README.md +621 -0
  8. package/plugins/sp/agents/expert-spur.md +109 -0
  9. package/plugins/sp/agents/super-coder.md +126 -0
  10. package/plugins/sp/agents/super-planner.md +283 -0
  11. package/plugins/sp/agents/super-reviewer.md +154 -0
  12. package/plugins/sp/commands/dev-arch.md +30 -0
  13. package/plugins/sp/commands/dev-brainstorm.md +40 -0
  14. package/plugins/sp/commands/dev-changelog.md +28 -0
  15. package/plugins/sp/commands/dev-daily.md +29 -0
  16. package/plugins/sp/commands/dev-debug.md +29 -0
  17. package/plugins/sp/commands/dev-dogfood.md +33 -0
  18. package/plugins/sp/commands/dev-featurechange.md +130 -0
  19. package/plugins/sp/commands/dev-find-conflict.md +51 -0
  20. package/plugins/sp/commands/dev-find-issue.md +76 -0
  21. package/plugins/sp/commands/dev-find-next.md +60 -0
  22. package/plugins/sp/commands/dev-fixall.md +33 -0
  23. package/plugins/sp/commands/dev-gitmsg.md +28 -0
  24. package/plugins/sp/commands/dev-gtd.md +97 -0
  25. package/plugins/sp/commands/dev-handover.md +26 -0
  26. package/plugins/sp/commands/dev-idea.md +50 -0
  27. package/plugins/sp/commands/dev-next.md +31 -0
  28. package/plugins/sp/commands/dev-parallel.md +30 -0
  29. package/plugins/sp/commands/dev-plan.md +46 -0
  30. package/plugins/sp/commands/dev-refine.md +48 -0
  31. package/plugins/sp/commands/dev-refineall.md +65 -0
  32. package/plugins/sp/commands/dev-refresh.md +32 -0
  33. package/plugins/sp/commands/dev-reverse.md +32 -0
  34. package/plugins/sp/commands/dev-review.md +31 -0
  35. package/plugins/sp/commands/dev-run.md +63 -0
  36. package/plugins/sp/commands/dev-runall.md +83 -0
  37. package/plugins/sp/commands/dev-simplify.md +39 -0
  38. package/plugins/sp/commands/dev-unit.md +29 -0
  39. package/plugins/sp/commands/dev-verify.md +48 -0
  40. package/plugins/sp/commands/dev-verifyall.md +72 -0
  41. package/plugins/sp/commands/dev-wrap.md +48 -0
  42. package/plugins/sp/commands/dev-wrapall.md +51 -0
  43. package/plugins/sp/commands/rule-add.md +18 -0
  44. package/plugins/sp/commands/rule-refine.md +18 -0
  45. package/plugins/sp/commands/rule-scan.md +18 -0
  46. package/plugins/sp/commands/spur-init.md +22 -0
  47. package/plugins/sp/commands/workflow-add.md +18 -0
  48. package/plugins/sp/commands/workflow-refine.md +18 -0
  49. package/plugins/sp/hooks/agent-hint.ts +60 -0
  50. package/plugins/sp/hooks/careful-guard.ts +147 -0
  51. package/plugins/sp/hooks/context-post-tool.ts +325 -0
  52. package/plugins/sp/hooks/context-session-start.ts +182 -0
  53. package/plugins/sp/hooks/context-session-stop.ts +95 -0
  54. package/plugins/sp/hooks/hooks.json +51 -0
  55. package/plugins/sp/hooks/pi/guard-extension.ts +341 -0
  56. package/plugins/sp/hooks/task-write-guard.ts +84 -0
  57. package/plugins/sp/plugin.json +8 -0
  58. package/plugins/sp/scripts/batch-preflight.ts +204 -0
  59. package/plugins/sp/scripts/daily-summary/daily-summary.ts +606 -0
  60. package/plugins/sp/scripts/daily-summary/logger.ts +28 -0
  61. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +363 -0
  62. package/plugins/sp/scripts/dogfood-testing/validate-report.ts +168 -0
  63. package/plugins/sp/scripts/feature-sync-bounded.ts +451 -0
  64. package/plugins/sp/scripts/stage-registry-adapter.ts +1341 -0
  65. package/plugins/sp/scripts/task-size-precheck.ts +202 -0
  66. package/plugins/sp/scripts/validate-commands.ts +651 -0
  67. package/plugins/sp/scripts/validate-flag-contracts.ts +875 -0
  68. package/plugins/sp/skills/brainstorm/SKILL.md +361 -0
  69. package/plugins/sp/skills/brainstorm/agents/openai.yaml +14 -0
  70. package/plugins/sp/skills/brainstorm/examples/ideation-example.md +209 -0
  71. package/plugins/sp/skills/brainstorm/metadata.openclaw +7 -0
  72. package/plugins/sp/skills/brainstorm/references/grilling-interview.md +68 -0
  73. package/plugins/sp/skills/brainstorm/references/workflows.md +255 -0
  74. package/plugins/sp/skills/branch-workflow/SKILL.md +109 -0
  75. package/plugins/sp/skills/branch-workflow/references/branch-lifecycle.md +69 -0
  76. package/plugins/sp/skills/branch-workflow/references/worktree-patterns.md +100 -0
  77. package/plugins/sp/skills/code-implementation/SKILL.md +203 -0
  78. package/plugins/sp/skills/code-implementation/references/debugging.md +64 -0
  79. package/plugins/sp/skills/code-implementation/references/implementation-patterns.md +113 -0
  80. package/plugins/sp/skills/code-improvement/SKILL.md +231 -0
  81. package/plugins/sp/skills/code-improvement/references/deepening-signals.md +205 -0
  82. package/plugins/sp/skills/code-review/SKILL.md +112 -0
  83. package/plugins/sp/skills/code-review/references/receiving-code-review.md +70 -0
  84. package/plugins/sp/skills/code-review/references/review-lenses.md +117 -0
  85. package/plugins/sp/skills/code-review/references/self-review-checklist.md +53 -0
  86. package/plugins/sp/skills/code-review/references/verification-before-completion.md +68 -0
  87. package/plugins/sp/skills/code-simplification/SKILL.md +225 -0
  88. package/plugins/sp/skills/code-testing/SKILL.md +108 -0
  89. package/plugins/sp/skills/code-testing/references/stacks/bun-ts.md +165 -0
  90. package/plugins/sp/skills/code-testing/references/stacks/go.md +88 -0
  91. package/plugins/sp/skills/code-testing/references/stacks/python.md +117 -0
  92. package/plugins/sp/skills/code-testing/references/test-loop-breaker.md +37 -0
  93. package/plugins/sp/skills/code-testing/references/test-output-discipline.md +52 -0
  94. package/plugins/sp/skills/code-testing/references/unit-testing.md +212 -0
  95. package/plugins/sp/skills/code-verification/SKILL.md +535 -0
  96. package/plugins/sp/skills/code-verification/references/code-improvement.md +39 -0
  97. package/plugins/sp/skills/code-verification/references/secu-review.md +94 -0
  98. package/plugins/sp/skills/code-verification/references/verdict-schema.md +141 -0
  99. package/plugins/sp/skills/conflict-finding/SKILL.md +254 -0
  100. package/plugins/sp/skills/conflict-finding/references/authority-resolution.md +258 -0
  101. package/plugins/sp/skills/conflict-finding/references/comparison-protocol.md +277 -0
  102. package/plugins/sp/skills/conflict-finding/references/finding-contract.md +346 -0
  103. package/plugins/sp/skills/conflict-finding/references/remediation-routing.md +276 -0
  104. package/plugins/sp/skills/daily-summary/SKILL.md +171 -0
  105. package/plugins/sp/skills/daily-summary/agents/openai.yaml +13 -0
  106. package/plugins/sp/skills/doc-evolve/SKILL.md +175 -0
  107. package/plugins/sp/skills/doc-evolve/references/operations.md +93 -0
  108. package/plugins/sp/skills/dogfood-testing/SKILL.md +608 -0
  109. package/plugins/sp/skills/dogfood-testing/references/monitor-ledger.md +211 -0
  110. package/plugins/sp/skills/dogfood-testing/references/report-template.md +351 -0
  111. package/plugins/sp/skills/doubt-driven-development/SKILL.md +136 -0
  112. package/plugins/sp/skills/functional-review/SKILL.md +364 -0
  113. package/plugins/sp/skills/functional-review/references/verdict-schema.md +133 -0
  114. package/plugins/sp/skills/indexed-context/SKILL.md +164 -0
  115. package/plugins/sp/skills/issue-finding/SKILL.md +442 -0
  116. package/plugins/sp/skills/issue-finding/agents/openai.yaml +15 -0
  117. package/plugins/sp/skills/issue-finding/examples/expected-findings.json +27 -0
  118. package/plugins/sp/skills/issue-finding/examples/session-test-loop.jsonl +23 -0
  119. package/plugins/sp/skills/issue-finding/references/session-formats.md +151 -0
  120. package/plugins/sp/skills/next-feature/SKILL.md +125 -0
  121. package/plugins/sp/skills/next-feature/references/handoff-routing.md +92 -0
  122. package/plugins/sp/skills/next-feature/references/proposal-contract.md +49 -0
  123. package/plugins/sp/skills/next-feature/references/ranking-rubric.md +52 -0
  124. package/plugins/sp/skills/next-feature/references/signal-derivation.md +67 -0
  125. package/plugins/sp/skills/next-router/SKILL.md +181 -0
  126. package/plugins/sp/skills/next-router/references/messages.md +90 -0
  127. package/plugins/sp/skills/next-router/references/routing-table.md +216 -0
  128. package/plugins/sp/skills/parallel-execution/SKILL.md +148 -0
  129. package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +109 -0
  130. package/plugins/sp/skills/parallel-execution/references/fan-out-patterns.md +101 -0
  131. package/plugins/sp/skills/parallel-execution/references/result-synthesis.md +94 -0
  132. package/plugins/sp/skills/reverse-engineering/SKILL.md +375 -0
  133. package/plugins/sp/skills/reverse-engineering/agents/openai.yaml +18 -0
  134. package/plugins/sp/skills/source-driven-development/SKILL.md +124 -0
  135. package/plugins/sp/skills/spec-decomposition/SKILL.md +117 -0
  136. package/plugins/sp/skills/spec-decomposition/references/decomposition.md +539 -0
  137. package/plugins/sp/skills/spur-cli/SKILL.md +133 -0
  138. package/plugins/sp/skills/spur-cli/references/agent.md +179 -0
  139. package/plugins/sp/skills/spur-cli/references/features/acceptance-criteria.md +82 -0
  140. package/plugins/sp/skills/spur-cli/references/features/hierarchy-mece.md +177 -0
  141. package/plugins/sp/skills/spur-cli/references/features/roadmap-priority.md +84 -0
  142. package/plugins/sp/skills/spur-cli/references/features/verbs.md +122 -0
  143. package/plugins/sp/skills/spur-cli/references/features.md +234 -0
  144. package/plugins/sp/skills/spur-cli/references/init.md +119 -0
  145. package/plugins/sp/skills/spur-cli/references/message.md +98 -0
  146. package/plugins/sp/skills/spur-cli/references/rules/authoring-rules.md +212 -0
  147. package/plugins/sp/skills/spur-cli/references/rules/fine-tuning.md +148 -0
  148. package/plugins/sp/skills/spur-cli/references/rules/operations.md +228 -0
  149. package/plugins/sp/skills/spur-cli/references/rules/validation-and-extension.md +129 -0
  150. package/plugins/sp/skills/spur-cli/references/rules.md +209 -0
  151. package/plugins/sp/skills/spur-cli/references/serve.md +58 -0
  152. package/plugins/sp/skills/spur-cli/references/tasks/l3-guard-cheatsheet.md +98 -0
  153. package/plugins/sp/skills/spur-cli/references/tasks/section-editing.md +95 -0
  154. package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +361 -0
  155. package/plugins/sp/skills/spur-cli/references/tasks.md +280 -0
  156. package/plugins/sp/skills/spur-cli/references/team.md +133 -0
  157. package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +226 -0
  158. package/plugins/sp/skills/spur-cli/references/workflows/operations.md +211 -0
  159. package/plugins/sp/skills/spur-cli/references/workflows/validation-and-extension.md +129 -0
  160. package/plugins/sp/skills/spur-cli/references/workflows.md +355 -0
  161. package/plugins/sp/skills/spur-dev/SKILL.md +224 -0
  162. package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +196 -0
  163. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +680 -0
  164. package/plugins/sp/skills/spur-dev/references/decision-brief.md +80 -0
  165. package/plugins/sp/skills/spur-dev/references/dev-operations.md +546 -0
  166. package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +164 -0
  167. package/plugins/sp/skills/spur-dev/references/execution-batch.md +790 -0
  168. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +352 -0
  169. package/plugins/sp/skills/spur-dev/references/feature-link-helper.md +191 -0
  170. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +417 -0
  171. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +171 -0
  172. package/plugins/sp/skills/spur-dev/references/glossary.md +95 -0
  173. package/plugins/sp/skills/spur-dev/references/idea-evaluation.md +80 -0
  174. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +120 -0
  175. package/plugins/sp/skills/spur-dev/references/planning-workflow.md +302 -0
  176. package/plugins/sp/skills/spur-dev/references/product-planning.md +206 -0
  177. package/plugins/sp/skills/spur-dev/references/section-batching.md +24 -0
  178. package/plugins/sp/skills/sys-architecture/SKILL.md +155 -0
  179. package/plugins/sp/skills/sys-architecture/references/decision-method.md +137 -0
  180. package/plugins/sp/skills/sys-architecture/references/upkeep-survey.md +75 -0
  181. package/plugins/sp/skills/sys-debugging/SKILL.md +228 -0
  182. package/plugins/sp/skills/sys-debugging/references/debugging-protocol.md +62 -0
  183. package/plugins/sp/skills/test-driven-development/SKILL.md +248 -0
  184. package/plugins/sp/skills/wayfinder/SKILL.md +292 -0
  185. package/spur.js +6035 -4963
@@ -0,0 +1,608 @@
1
+ ---
2
+ name: dogfood-testing
3
+ description: "Drive a testee (skill/command/CLI) end-to-end as a real user, fix within a bounded retry budget, monitor with a live ledger, emit a structured report. Triggers: \"dogfood this\", \"drive this command end-to-end\", \"test this skill as a user\", \"dogfood report\"."
4
+ license: Apache-2.0
5
+ metadata:
6
+ author: spur
7
+ version: "1.2"
8
+ protocol: "sp:dogfood-testing@1.2"
9
+ platforms: "claude-code,codex,openclaw,opencode,antigravity"
10
+ interactions:
11
+ - pipeline
12
+ - reviewer
13
+ modes:
14
+ - observe
15
+ - fix
16
+ phases:
17
+ - plan
18
+ - execute
19
+ - monitor
20
+ - report
21
+ openclaw:
22
+ emoji: "🐕"
23
+ ---
24
+
25
+ # Dogfood Testing — The Backbone Skill
26
+
27
+ `sp:dogfood-testing` drives an agent skill, slash command, or CLI invocation **end-to-end** as a
28
+ real user would: run the testee step by step, fix what breaks (within a bounded retry budget),
29
+ monitor the whole run with a live ledger, and emit a structured report of what happened, what broke,
30
+ what was fixed, and what should improve.
31
+
32
+ This is the codification of the manual dogfooding loop run across tasks `0109`–`0114` and `0124`.
33
+ It backs the `/sp:dev-dogfood` thin-wrapper command — the command parameterizes the testee and
34
+ sinks; this skill owns the protocol.
35
+
36
+ ## The 4-phase protocol at a glance
37
+
38
+ ```
39
+ testee (a /sp:... command, Skill(...), or shell CLI invocation)
40
+ → PLAN classify + derive steps + open dual artifacts (live + docs/dogfood) with status:running
41
+ → EXECUTE run each step as a user; on failure, bounded diagnose→fix→re-run (or observe-only)
42
+ → MONITOR dual-write ledger row to disk on every step resolve — never reconstruct from memory
43
+ → REPORT finalize-or-abort (non-skippable): status complete|aborted, Cost block, both paths, footer
44
+ ```
45
+
46
+ ## Arguments
47
+
48
+ The command forwards these via `$ARGUMENTS`:
49
+
50
+ | Argument | Description | Default |
51
+ |----------|-------------|---------|
52
+ | `testee` | What to exercise — a slash command, agent skill, or CLI invocation (positional, required). Quote it if it contains flags. | (required) |
53
+ | `--agent <name\|auto>` | **Testee-scoped** agent: the agent the **testee** runs under, forwarded into the testee invocation. The driver (this skill) always runs in the current session. **Omit it** to forward nothing — the testee runs under its own default. See [§Testee-scoped agent](#testee-scoped-agent). | (omitted → forward nothing) |
54
+ | `--max-retry <n>` | Fix attempts per failed step. The **default is `2`** (fix mode): apply `Edit`/`Write` fixes to the working tree, up to 2 attempts per step. This flag is **mandatory** for two independent mutation sources: (a) pipeline-driving testees and (b) testees carrying a mutating `--fix` mode (`--fix all` / `--fix blockers-first`). Pass `--max-retry 0` for **observe-only**, or `--max-retry N` to acknowledge fix-mode mutation risk. For a mutating-`--fix` testee, `--max-retry 0` bounds the **driver only** — the testee still mutates the tree. | `2` unless the testee is pipeline-driving or carries a mutating `--fix` mode |
55
+ | `--save` | **Back-compat no-op for delivery.** Reports are always written to `docs/dogfood/…` and `.spur/run/dogfood/<run_id>.md`. The flag still documents/prints the report path. | always-on (flag optional) |
56
+ | `--task` | File findings as a review-template task via `spur task create --template review`. | off |
57
+ | `--chain-follow` | **Operator override for `--next` chains.** Permits the driver to follow the chain into named chained-leg artifacts (`.spur/run/<wbs>-verdict.json`, task-file section diffs, review tables) and attribute normally instead of stopping at the testing boundary. The flag licenses reading chained-leg evidence that already exists; it does NOT license the driver to execute the chained leg itself. Omit it to keep stop-at-testing as the default. See [§`--next` chain stop-at-testing](#next-chain-stop-at-testing) and [§Platform boundary (Claude Code)](#claude-code). | off |
58
+ | `--full` | Full report verbosity — emit all six sections even when a step set is sparse. Default omits empty narrative sections. | off |
59
+
60
+ > **Single-dash lenient parsing (R6b).** The argument parser accepts `-flag value` as equivalent to
61
+ > `--flag value` for `--max-retry`, `--agent`, `--save`, `--task`, `--full` (and their `--fix`/
62
+ > `--steps` siblings). This is intentional back-compat for terminal ergonomics, but it collides with
63
+ > the mutating-fix refuse-gate, which keys on `--max-retry` presence: an operator typing
64
+ > `-max-retry 3` on a pipeline-driving testee would bypass the refuse message if the gate ran on
65
+ > the raw string. It does not — the gate runs on the **normalized** token after parse. The driver
66
+ > MUST echo the normalized flag in its Phase-1 plan output (`Plan: testee invoked as …
67
+ > --max-retry 3 …`), not the operator's original spelling, so the operator sees which form was
68
+ > honored. A run that silently parsed `-max-retry 3` without echoing the normalized form is a P4
69
+ > finding (verify-0293) — the parsing is allowed, the silent treatment is not.
70
+
71
+ > ⚠️ **Repo-mutation warning.** The default is **fix mode (`--max-retry 2`)** — it applies
72
+ > `Edit`/`Write` fixes to the working tree as it finds breakages. For a non-mutating run, opt into
73
+ > **observe-only** with `--max-retry 0`: monitor and report, never touch files, full findings report
74
+ > still produced. Omission is ambiguous and MUST fail before planning when **either** of two
75
+ > independent mutation sources is present:
76
+ >
77
+ > - **Pipeline-driving testees** — tokens
78
+ > [`--next`, `dev-runall`, `dev-wrapall`, `dev-run`, `dev-wrap`, `dev-idea`,
79
+ > `runall`, `wrapall`, `run`, `wrap`, `idea`] matched as a **distinct hyphen-word**
80
+ > (machine-checked by
81
+ > [`detectPipelineDriving`](../../scripts/dogfood-testing/detect-pipeline-driving.ts);
82
+ > see [§Pipeline-driving word-boundary contract](#pipeline-driving-word-boundary-contract))
83
+ > → `⚠ pipeline-driving testee detected; pass --max-retry 0 (observe-only) or --max-retry N (fix mode, tree mutation acknowledged)`.
84
+ > - **Mutating `--fix` modes** — `--fix all` / `--fix blockers-first`, boundary-guarded via
85
+ > [`hasMutatingFixMode`](../../scripts/dogfood-testing/detect-pipeline-driving.ts) (never matches
86
+ > `--fix none` / `--focus all` / `--prefix all`). No pipeline token required: a verify/review leg
87
+ > with `--fix all` mutates the tree on its own (0280 dogfood P2, task 0293). Honesty note:
88
+ > `--max-retry 0` here bounds **the driver only** — the testee still mutates the tree — so the
89
+ > refuse message is
90
+ `⚠ mutating --fix mode detected (--fix all | --fix blockers-first); pass --max-retry 0 (observe-only for the driver; the testee still mutates the tree) or --max-retry N (fix mode, driver + testee both mutate)`.
91
+
92
+ ## Phase 1 — Plan
93
+
94
+ 0. **Refuse ambiguous mutation-source testees (live CLI gate — not prose-only).** Before deriving
95
+ steps, run the machine-checked detector as a shell command (do **not** re-implement the matcher
96
+ in-agent):
97
+
98
+ ```bash
99
+ bun plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts \
100
+ --testee "<raw testee string>" \
101
+ [--max-retry-present] # pass this flag only when the dogfood invocation included --max-retry
102
+ ```
103
+
104
+ - Exit **2** → print the stdout refuse line and **stop** (do not plan). The CLI refuses on either
105
+ of two independent mutation sources (task 0293); print whichever refuse message it emits:
106
+ - pipeline-driving: `⚠ pipeline-driving testee detected; pass --max-retry 0 (observe-only) or --max-retry N (fix mode, tree mutation acknowledged)`.
107
+ - mutating `--fix`: `⚠ mutating --fix mode detected (--fix all | --fix blockers-first); pass --max-retry 0 (observe-only for the driver; the testee still mutates the tree) or --max-retry N (fix mode, driver + testee both mutate)`.
108
+ - Exit **0** → proceed. Do not auto-substitute `--max-retry 0`.
109
+ - The matcher contract is unit-checked by `tests/dogfood-testing/pipeline-detect.test.ts`.
110
+ See [§Pipeline-driving word-boundary contract](#pipeline-driving-word-boundary-contract) and
111
+ [§Mutating `--fix` mode contract](#mutating---fix-mode-contract).
112
+ 1. **Resolve + classify** the testee: slash command (`/sp:...`), agent skill (`Skill(...)`), or shell
113
+ CLI (`spur ...`, `bun run ...`). Everything before the first dogfood flag is the testee; if it
114
+ carries its own flags, it must be quoted.
115
+ 2. **Derive ordered steps** from the testee's own docstring / `argument-hint` / workflow. If no step
116
+ list can be derived, treat the whole invocation as one step.
117
+ 2b. **Implement-heavy advisory (W8 — emit at derivation time).** Immediately after step derivation,
118
+ re-run the gate with the derived step labels:
119
+
120
+ ```bash
121
+ bun plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts \
122
+ --testee "<raw testee string>" \
123
+ --max-retry-present \
124
+ --steps "step1 label||step2 label||..."
125
+ ```
126
+
127
+ When stdout prints
128
+ `⚠ implement-heavy pipeline dogfood: prefer --max-retry 0 (observe-only) or step-split; operator --max-retry N overrides`,
129
+ surface that line in the live report §1/§2 **and** continue only because the operator already
130
+ passed an explicit `--max-retry`. Prefer observe-only or step-split on the next run. Record the
131
+ advisory in the ledger `Finding` column for implement-heavy steps. See
132
+ [§Cost segmentation for implement-heavy steps](#cost-segmentation-for-implement-heavy-steps).
133
+ 3. **Open dual artifacts (always-on delivery — not gated on `--save`).**
134
+ - Generate `run_id` (uuid or timestamp-slug).
135
+ - `mkdir -p .spur/run/dogfood docs/dogfood`.
136
+ - Write **both** files with identical YAML frontmatter (`status: running`, testee, mode,
137
+ timestamps, paths, `protocol: sp:dogfood-testing@1.2`) + six section heading stubs + empty
138
+ Monitor Ledger table:
139
+ - Live: `.spur/run/dogfood/<run_id>.md`
140
+ - Report: `docs/dogfood/YYYY-MM-DD-<testee-slug>-dogfood.md`
141
+ - Canonical frontmatter and skeleton: [report-template.md](references/report-template.md).
142
+ - Column contract + dual-write: [monitor-ledger.md](references/monitor-ledger.md).
143
+ - **R2 workspace fingerprint (fix-mode and mutating-`--fix` dogfoods only).** When the run is
144
+ fix-mode or a mutating-`--fix` testee, record a `workspace_fingerprint` block (git HEAD +
145
+ `git status --porcelain` hash + timestamp) in the live ledger frontmatter. See
146
+ [§Workspace-drift guard](#workspace-drift-guard-r2--task-0296).
147
+
148
+ ## Phase 2 — Execute + bounded fix
149
+
150
+ For each step, in order:
151
+
152
+ 1. **Run** the step as a user would — forwarding `--agent` into the testee invocation (§below).
153
+ 2. **Success** → log the row, advance.
154
+ 3. **Failure** →
155
+ - `--max-retry 0` → log as an **Unresolved issue** with diagnosis, mutate nothing, advance.
156
+ - else → diagnose root cause → apply the smallest `Edit`/`Write` fix → **re-run the same step**,
157
+ up to `--max-retry` times, but **first re-take the workspace snapshot and check drift**
158
+ (R2 — see [§Workspace-drift guard](#workspace-drift-guard-r2--task-0296)). If drift is detected,
159
+ append a `drift:external` warning row and emit a P2 finding; never attribute drifted files to
160
+ the run or claim them as the fix. Pass within budget → **Fixed issue** (record the fix); still
161
+ failing → **Unresolved issue** (record everything tried). Either way, advance — partial signal
162
+ is the point.
163
+
164
+ **Fix discipline.** Fix the testee or its real dependency. Never weaken the testee, stub the failure
165
+ away, or `--no-verify` past a gate to make a step "pass". A fix that hides the bug you are hunting is
166
+ a **finding**, not a fix.
167
+
168
+ **Implement-heavy derived steps.** Each derived step that itself chains into further pipeline work
169
+ multiplies the run's blast radius — when a step is implement-heavy (a `--next` chain to `dev-run`, a
170
+ derived `wrap`/`wrapall`, a verify/review leg carrying a mutating repair mode `--fix all` /
171
+ `--fix blockers-first` — `--fix none` stays observational — or any testee that mutates more than its
172
+ own arguments), surface this in
173
+ the ledger row's `Finding` column and prefer **observe-only** or **step-splitting** rather than
174
+ driving the chain under fix mode. See
175
+ [§Cost segmentation for implement-heavy steps](#cost-segmentation-for-implement-heavy-steps) and
176
+ [§`--next` chain stop-at-testing](#next-chain-stop-at-testing).
177
+
178
+ ## Phase 3 — Monitor
179
+
180
+ The ledger is updated **live on disk** during Phase 2 and is the single source of truth for the
181
+ report — the report is assembled from the files, not from memory.
182
+
183
+ On **every** step resolve:
184
+
185
+ 1. Append/update the ledger row on the **live** file first.
186
+ 2. Mirror the same row to the **report** path under `docs/dogfood/`.
187
+ 3. Do **not** batch rows until Phase 4.
188
+
189
+ The final report MUST include a `### 3. Monitor Ledger` section containing those rows, and the
190
+ ledger's data-row count MUST equal the `**Steps:** N derived, N executed` declared in §2 of the report (N/A steps
191
+ documented explicitly as rows) — the cardinality rule in
192
+ [monitor-ledger.md](references/monitor-ledger.md). Full
193
+ methodology, column contract, token/cache estimation, multi-source Cost honesty, the cache-health
194
+ finding rule, and the **cache-conservation discipline** live in
195
+ **[monitor-ledger.md](references/monitor-ledger.md)**. Apply the conservation discipline while
196
+ monitoring — low cache% is usually the driver re-fetching data it already holds.
197
+
198
+ ## Phase 4 — Report (finalize-or-abort — non-skippable)
199
+
200
+ **Terminal gate.** Before this skill may stop (PASS / PARTIAL / FAIL / observe-only end / abort /
201
+ any early exit), the driver MUST run the finalize-or-abort checklist. Skipping it is a **driver
202
+ contract violation**.
203
+
204
+ 1. Set frontmatter `status: complete` or `status: aborted` and `finished_at`.
205
+ 2. **Structure scrub (@1.2).** All six mandatory section headings exist **exactly once each**
206
+ (`### 1.` … `### 6.` — duplicates refuse `complete`). §5 Issues carries both `#### Fixed` and
207
+ `#### Unresolved` (with `(none)` when empty). Unfinished narrative sections:
208
+ `⚠ incomplete — not reached` — never invent What-We-Did / Issues / Findings fiction, and no
209
+ leftover "run in progress" markers may survive finalization.
210
+ 3. **Ledger cardinality (@1.2).** Monitor Ledger data rows MUST equal the `**Steps:** N derived, N executed`
211
+ declared in §2 (N/A steps documented explicitly as rows). A mismatch refuses `complete`.
212
+ 4. Write the **Cost** block under §2 (ledger `~estimate` + Method + confidence; `Meter: n/a` or
213
+ optional ccusage/agent usage when real). For any `chained:<step>` ledger row whose meter is not
214
+ observable, Fresh/Cached MUST be `~unknown` (or Cached `~0` with Basis `unobservable`) **and**
215
+ emit finding `P3 — chained-step cost not observable` — never invent chained totals.
216
+ 5. **R2 drift check at finalize.** If a workspace fingerprint was recorded in Phase 1, re-take
217
+ the snapshot and diff against baseline minus the run's own touched files. If drift is detected,
218
+ append a `drift:external` warning row to the ledger and emit a mandatory P2 report finding
219
+ (under §6 Findings) stating the run's evidence is degraded, not voided. Never claim drifted
220
+ files as run work. See [§Workspace-drift guard](#workspace-drift-guard-r2--task-0296).
221
+ 6. Sync final content to **both** live and report paths (always — not gated on `--save`).
222
+ 7. **Footer mandatory (@1.2).** Print the mandatory summary footer with **both** `[Live: …]` and
223
+ `[Report: …]` always, **and mirror the footer block at the end of the report file**. A report
224
+ without the footer cannot set `status: complete`.
225
+ 8. **Self-validate (task 0278 R6 — non-skippable).** Run the machine checker on the report body
226
+ **before** claiming `status: complete`:
227
+
228
+ ```bash
229
+ bun plugins/sp/scripts/dogfood-testing/validate-report.ts --file <report-path>
230
+ ```
231
+
232
+ Exit **0** → proceed. Exit **2** → set `status: aborted`, list every error code under §5
233
+ `#### Unresolved`, do **not** claim complete (closes non-@1.2 shapes like `## §1` without
234
+ `### 1.`–`### 6.` / footer). Exit **1** → usage/IO failure; fix path and re-run.
235
+ 9. **Refusal rule (@1.2).** If any check above fails, set `status: aborted` (never `complete`) and
236
+ list each failed check under §5 `#### Unresolved`.
237
+
238
+ Full section contract, frontmatter, Cost shape, and footer:
239
+ **[report-template.md](references/report-template.md)**.
240
+
241
+ **Sinks** (composable):
242
+ - **Always-on report files** → live + `docs/dogfood/YYYY-MM-DD-<testee-slug>-dogfood.md` (see Phase 1).
243
+ - `--save` → no-op for delivery; still print/document the report path (back-compat).
244
+ - `--task` → file findings as a review task (`spur task create --template review`), writing the
245
+ **Findings** into the task's `#### Review Findings` table under `### Background`. See
246
+ [report-template.md → Task sink](references/report-template.md) for the `task check` L3 contract.
247
+
248
+ ## Testee-scoped agent
249
+
250
+ `dogfood-testing` is a **driver** that runs *other* testees, so `--agent` here is different from the
251
+ standard `/sp:dev-*` semantics: it sets the agent the **testee** runs under, **not** the driver.
252
+
253
+ - The **driver** (this skill — planning, monitoring, reporting) always runs in the **current
254
+ session**. `--agent` never changes that.
255
+ - The **testee** invocation receives the forwarded `--agent`. Concretely: append/splice `--agent
256
+ <value>` into the testee's own flags before running it.
257
+
258
+ ```
259
+ /sp:dev-dogfood "/sp:dev-run 0125 --auto" --agent codex
260
+ ↓ driver = current session (monitors, reports)
261
+ ↓ testee runs as: /sp:dev-run 0125 --auto --agent codex
262
+ ```
263
+
264
+ If the testee does not accept `--agent` (e.g. a pure-inline command), record that as a **finding**
265
+ ("testee ignores `--agent`") rather than forcing the flag. **Omitting `--agent` (the default)
266
+ forwards nothing** — the testee runs under whatever it would default to (which, for a `spur agent
267
+ run`-backed testee, is `--agent auto` → the configured default executor). There is no `inherit` or
268
+ `current` token: "run under the current agent" is simply the default for an inline slash command
269
+ (it executes in this session) and is **not** expressible for the spawned `spur agent run` path,
270
+ which always launches a fresh agent subprocess.
271
+
272
+ ## When to use
273
+
274
+ - Debugging or hardening an agent skill / slash command you are actively developing.
275
+ - Validating a command works end-to-end before shipping it.
276
+ - Producing a structured findings report (and optionally a fix task) from a real run.
277
+
278
+ Do **not** use this skill for:
279
+ - Requirements-traceability verdicts — use `sp:code-verification` (`/sp:dev-verify`).
280
+ - SECU code review of a diff — use `sp:code-verification` (`/sp:dev-review`).
281
+ - Running a task through the fix pipeline — use `sp:spur-dev` (`/sp:dev-run`).
282
+
283
+ ## Gotchas
284
+
285
+ 1. **Observe-only for unfamiliar testees.** The default is fix mode (`--max-retry 2`), which mutates
286
+ the working tree. Against any testee you don't own or fully trust — or one that drives a long,
287
+ mutating pipeline — pass `--max-retry 0` first and inspect the findings before letting it apply
288
+ fixes.
289
+ 2. **The ledger is live on disk, not reconstructed.** Honest fixed-vs-unresolved accounting depends
290
+ on dual-writing each step *as it happens* to both artifacts. Reconstructing at the end produces
291
+ fiction. Working-memory-only ledgers are a contract violation.
292
+ 3. **A hiding fix is a finding.** If "fixing" a step would mask the bug, log it as a finding and
293
+ leave the step unresolved.
294
+ 4. **Token numbers are estimates, but cache math is not free-form.** A skill cannot read its own
295
+ exact token meter, so label numbers `~estimate` and put Method + confidence in the Cost block;
296
+ however, cache% must be recomputable from Monitor Ledger row sums. Never invent or reuse a fixed
297
+ percentage. Optional meters (`ccusage`, agent usage) are session/day scope — never fake per-step.
298
+ 5. **Testee-scoped `--agent`.** Don't confuse the driver agent (always current) with the testee
299
+ agent (the forwarded value).
300
+ 6. **Stale command snapshot.** Slash-command definitions are snapshotted at session start. If you
301
+ just edited the testee command's own `.md` (or this command's), invoking it in the **same
302
+ session** may run the **old** body. Verify in a fresh session, or invoke the backing skill
303
+ directly, before trusting an in-session dogfood of a command you just changed. Note same-session
304
+ edits under §1 Testee when relevant.
305
+ 7. **Finalize-or-abort is non-skippable.** Ending a run without updating `status`, syncing both
306
+ paths, and printing the footer with `[Live:]` + `[Report:]` fails the delivery contract — even if
307
+ the testee itself passed.
308
+ 8. **`--save` is not required for a file.** Dual artifacts are always-on. Do not skip writing
309
+ `docs/dogfood/` because the operator omitted `--save`.
310
+ 9. **Pipeline-driving + implement-heavy derived step ⇒ prefer observe-only or step-split.** When the
311
+ Phase 1.2b CLI emits the implement-heavy advisory (pipeline-driving + implement-heavy step), the
312
+ dogfood run is **recursive**: it tests a pipeline that mutates the repo while the driver may also
313
+ be in fix mode. Two mutation sources make attribution impossible. The advisory is **emitted at
314
+ derivation time** (not only as docs-time guidance). Operator's explicit `--max-retry N` proceeds;
315
+ prefer `--max-retry 0` or step-split next time. See
316
+ [§Cost segmentation for implement-heavy steps](#cost-segmentation-for-implement-heavy-steps).
317
+ 10. **`--next` chain stop-at-testing when provenance is missing.** A `--next` chain (refine→run,
318
+ run→verify, etc.) runs each leg as its own pipeline stage. If the dogfood driver cannot observe
319
+ the chain's intermediate artifacts (task file sections, verify verdicts, review tables) — because
320
+ the chain ran in a subagent, a different session, or the artifacts were never written — the driver
321
+ MUST stop at the **testing boundary** of the chained step and report "chained-step provenance
322
+ missing; cannot attribute outcome" rather than fabricating an outcome from the final state. Do not
323
+ change the chained lifecycle's code (dev-run/dev-verify); this is a reporting discipline, not a
324
+ lifecycle change. See [§`--next` chain stop-at-testing](#next-chain-stop-at-testing).
325
+
326
+ ## Pipeline-driving word-boundary contract
327
+
328
+ Pipeline-driving detection is **word-boundary**, not leading-space substring. The live gate is:
329
+
330
+ ```bash
331
+ bun plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts --testee "<testee>" [--max-retry-present] [--steps "…"] [--json]
332
+ ```
333
+
334
+ | Token shape | Examples | Matches | Rejects |
335
+ |-------------|----------|---------|---------|
336
+ | Flag / complete | `--next`, `dev-run`, `dev-runall`, `dev-wrap`, `dev-wrapall`, `dev-idea` | `/sp:dev-run 0125`, bare `--next` | `--next-gen`, `dev-runner` |
337
+ | Bare noun | `run`, `runall`, `wrap`, `wrapall`, `idea` | `task run 0042` | `runaway`, `wrapper`, `idealist` |
338
+
339
+ `-` is a **word character** for boundaries: a token must be a distinct hyphen-word. Contract tests:
340
+ `plugins/sp/tests/dogfood-testing/pipeline-detect.test.ts`. Helpers:
341
+ `detectPipelineDriving`, `isImplementHeavyStep`, `detectImplementHeavy`, `evaluateDogfoodGate` in
342
+ [`detect-pipeline-driving.ts`](../../scripts/dogfood-testing/detect-pipeline-driving.ts).
343
+
344
+ ## Mutating `--fix` mode contract
345
+
346
+ Task 0293 extended the refuse gate to a **second, independent** mutation source: a testee carrying
347
+ a mutating `--fix` mode — `--fix all` or `--fix blockers-first`. Boundary-guarded via
348
+ `hasMutatingFixMode` so it never matches `--fix none`, `--focus all`, `--prefix all`, or substrings
349
+ inside other flags. No pipeline token required: a verify/review leg with `--fix all` mutates the
350
+ tree on its own (0280 dogfood P2 — the `--fix all` pass was the sole mutation source for 11 dataset
351
+ files, a workflow edit, and 2 corpus writes).
352
+
353
+ | Token shape | Matches | Rejects |
354
+ |-------------|---------|---------|
355
+ | `--fix all` / `--fix=all` / `--fix all` (case-insensitive) | `/sp:dev-verify 0299 --fix all`, `--fix=All`, `--fix BLOCKERS-FIRST` | `--fix none`, `--focus all`, `--prefix all`, `--fix-all-gen` |
356
+
357
+ Refuse message (R2 honesty — `--max-retry 0` bounds **the driver only**; the testee still mutates):
358
+
359
+ ```
360
+ ⚠ mutating --fix mode detected (--fix all | --fix blockers-first); pass --max-retry 0
361
+ (observe-only for the driver; the testee still mutates the tree) or --max-retry N (fix mode,
362
+ driver + testee both mutate)
363
+ ```
364
+
365
+ This is **not** a new token in `PIPELINE_TOKENS` (R5/R6 — back-compat): pipeline-driving and
366
+ mutating-fix are checked by separate matchers, and pipeline-driving's refuse message wins when both
367
+ co-occur (its message is the superset — chain + tree mutation).
368
+
369
+ ## Workspace-drift guard (R2 — task 0296)
370
+
371
+ A fix-mode dogfood (`--max-retry ≥ 1`) or a mutating-`--fix` testee writes to the **shared working
372
+ tree**. A concurrent external writer — formatter, another agent, the operator's editor — is then
373
+ indistinguishable from testee/driver mutation in the ledger and report. The guard detects drift,
374
+ attributes it to the external writer, and never claims drifted files as run work.
375
+
376
+ **Additive only** — protocol stays `sp:dogfood-testing@1.2`; the new ledger/report fields are
377
+ optional so existing reports remain valid. No gate refuses a run on drift; drift degrades the
378
+ evidence (a warning + finding), never voids it.
379
+
380
+ ### Fingerprint (Phase 1)
381
+
382
+ Before the first testee step, record a **workspace fingerprint** in the live ledger frontmatter:
383
+
384
+ ```yaml
385
+ workspace_fingerprint:
386
+ head: <`git rev-parse HEAD`>
387
+ porcelain_hash: <stable hash of `git status --porcelain` output>
388
+ taken_at: <ISO-8601>
389
+ ```
390
+
391
+ The hash is over the raw `git status --porcelain` bytes (e.g. `shasum -a 256`). Store the snapshot
392
+ string is NOT required — the hash is enough to detect a change; the live file already records what
393
+ the run itself touched via ledger rows.
394
+
395
+ ### Drift check (before each fix application + once at Phase 4 finalize)
396
+
397
+ Re-take the snapshot and diff it against the baseline **minus files the run itself has touched**
398
+ (driver fixes + testee-attributed writes from the ledger `Fix Applied` column). Drift check points:
399
+
400
+ 1. Immediately before each Phase 2 fix application (so a fix isn't credited to drift, and drift
401
+ isn't credited to a fix).
402
+ 2. Once at Phase 4 finalize (so the final report acknowledges any drift that happened mid-run).
403
+
404
+ **Not** after every testee step — observe-only runs (`--max-retry 0`) stay zero-overhead. A run with
405
+ no fix applications and a clean tree at finalize needs no drift row.
406
+
407
+ ### What drift is — and is not
408
+
409
+ **Drift** = a tracked file changes that neither the driver nor the testee ledger row names.
410
+ **Explained** set = files named in ledger `Fix Applied` cells (driver fixes) plus files the testee
411
+ wrote that the driver recorded in the ledger (testee-attributed writes). Anything else in
412
+ `git status --porcelain` that is new or modified since baseline is drift.
413
+
414
+ ### On detecting drift
415
+
416
+ - Append a **warning ledger row** tagged `drift:external` in the Step column: paths in `Fix Applied`,
417
+ `Outcome: drift`, `Basis: <fingerprint diff>`. Do NOT mark the step PASSED/FIXED on account of
418
+ drift; the row records the drift, it does not change a step's outcome.
419
+ - Emit a **mandatory report finding** under §6 Findings — `P2 — workspace drift detected during
420
+ run; attribution to external writer` — naming the drifted paths and the snapshot delta. The report
421
+ explicitly states the run's evidence is degraded, not voided.
422
+ - The driver **never** claims drifted files as its own or the testee's work. A fix ledger row's
423
+ `Fix Applied` cites only the file:line the driver changed; drift rows cite the drifted paths
424
+ separately.
425
+
426
+ ### Worktree advisory (mutating dogfoods)
427
+
428
+ For fix-mode dogfoods of **pipeline-driving** or **mutating-`--fix`** testees (the two refuse-gate
429
+ cases above), the §Mutating `--fix` mode contract recommends running the dogfood in an **isolated
430
+ `git worktree`** so concurrent external writers cannot collide with the run. This is **advisory,
431
+ not a hard gate** — the refuse-gate semantics from task 0293 are unchanged. A worktree removes the
432
+ drift case entirely (no concurrent writer can reach the isolated checkout), which is why it is the
433
+ preferred setup for mutating dogfoods where the operator cares about clean attribution.
434
+
435
+ ## Step-splitting recipe (implement-heavy pipeline dogfoods)
436
+
437
+ When the Phase 1.2b advisory fires (or you know the testee is implement-heavy), **prefer two or
438
+ more non-recursive dogfood runs** over one nested fix-mode chain. Worked recipe:
439
+
440
+ **Bad (recursive fix-mode):** dogfood the whole refine→run→verify chain under `--max-retry N` —
441
+ the driver mutates while the testee pipeline also mutates; attribution fails.
442
+
443
+ ```bash
444
+ # Avoid unless you fully accept dual mutation:
445
+ /sp:dev-dogfood "/sp:dev-refine 0278 --auto --next" --max-retry 3 --full
446
+ ```
447
+
448
+ **Good (step-split):**
449
+
450
+ ```bash
451
+ # 1) Observe refine only (no tree mutation from the driver)
452
+ /sp:dev-dogfood "/sp:dev-refine 0278 --auto" --max-retry 0 --full
453
+
454
+ # 2) After refine is clean, dogfood implement/run alone
455
+ /sp:dev-dogfood "/sp:dev-run 0278 --auto --mode implement" --max-retry 2 --full
456
+
457
+ # 3) Dogfood verify as its own run (corpus gates only)
458
+ /sp:dev-dogfood "/sp:dev-verify 0278 --auto --next --force --focus all --fix all" --max-retry 2 --full
459
+ ```
460
+
461
+ Rules: one mutation source per dogfood run; use `--max-retry 0` for unfamiliar pipeline legs; keep
462
+ dual artifacts / finalize for each run. Linked from the implement-heavy advisory
463
+ (`⚠ implement-heavy pipeline dogfood: prefer --max-retry 0 (observe-only) or step-split…`).
464
+
465
+ ## Cost segmentation for implement-heavy steps
466
+
467
+ A dogfood run where a derived step is implement-heavy (the step itself writes code, runs a pipeline
468
+ leg, or otherwise mutates more than its own arguments) has **two cost sources** that MUST be
469
+ segregated in the Cost block and the ledger:
470
+
471
+ | Source | What it is | How to label in the ledger |
472
+ |--------|------------|----------------------------|
473
+ | Driver cost | Tokens the dogfood driver spent planning, monitoring, fixing, reporting | normal per-step `Fresh` / `Cached` columns |
474
+ | Chained-step cost | Tokens the testee's own pipeline leg spent (subagent invocations, file reads/writes inside `/sp:dev-run`, etc.) | a separate ledger row tagged `chained:<step>`; Fresh/Cached estimated from observed subagent output, or `~unknown` when not observable |
475
+
476
+ Rules:
477
+
478
+ 1. Never fold chained-step cost into the driver's row. The whole point of dogfooding a
479
+ pipeline-driving testee is to see what the *testee* costs to run, separately from what the driver
480
+ costs to monitor it.
481
+ 2. When the chained step ran in a subagent or session whose usage data the driver cannot read, label
482
+ the chained row `~unknown` and emit a **P3** finding: "chained-step cost not observable — candidate
483
+ for surfacing subagent usage in the driver context." Do not invent a number.
484
+ 3. The chained row still counts toward the aggregate cache% — but mark it pessimistically
485
+ (`Cached = ~0`) when the basis is missing, per the anti-fiction rule in
486
+ [monitor-ledger.md](references/monitor-ledger.md).
487
+
488
+ ## `--next` chain stop-at-testing
489
+
490
+ When a dogfood testee ends in `--next` (refine→run, run→verify, idea→plan→run), the chain runs
491
+ multiple lifecycle legs back-to-back. Each leg has its own testing boundary — the point past which the
492
+ dogfood driver cannot attribute an outcome to a specific leg's contract.
493
+
494
+ **Stop-at-testing rule.** If the driver cannot observe a chained leg's intermediate artifact (task
495
+ file section update, verify verdict, review table, pipeline transition), the driver STOPS at that
496
+ leg's testing boundary and reports:
497
+
498
+ ```
499
+ chained-leg <name>: provenance missing — intermediate artifact not observable from driver context
500
+ ```
501
+
502
+ Do NOT:
503
+
504
+ - Fabricate a PASS/FAIL for the chained leg from the repo's final state. The final state reflects
505
+ every leg's effect combined; attributing it to one leg is fiction.
506
+ - Change the chained lifecycle's code (`dev-run`, `dev-verify`, `dev-refine`) to emit artifacts the
507
+ dogfood driver can read. The chain's contract is owned by `sp:spur-dev`; this skill reports on it,
508
+ it does not alter it. Surface the gap as a finding instead.
509
+ - Silently skip the chained leg in the ledger. Record the row with outcome `provenance-missing` and a
510
+ P3 finding.
511
+
512
+ **`--chain-follow` (sanctioned override).** The operator passes `--chain-follow` to grant the
513
+ driver permission to read the chained leg's named artifacts (`.spur/run/<wbs>-verdict.json`,
514
+ task-file section diffs, review tables) after the leg completes and attribute normally. The flag
515
+ licenses **reading** chained-leg evidence that already exists — it does NOT license the driver to
516
+ execute the chained leg itself. The legacy "operator may direct" prose direction is still honored
517
+ for back-compat; `--chain-follow` is the explicit, machine-recognizable form. Omitting the flag
518
+ keeps stop-at-testing as the **default**. The flag is a driver attribute only — it does not change
519
+ `detect-pipeline-driving` gate semantics (it is not a testee mutation source). See
520
+ [§Arguments](#arguments).
521
+
522
+ ## Additional Resources
523
+
524
+ - [references/report-template.md](references/report-template.md) — the report section contract +
525
+ mandatory summary footer + task-sink L3 rule.
526
+ - [references/monitor-ledger.md](references/monitor-ledger.md) — the live-ledger column contract,
527
+ token/cache estimation heuristic, and the cache-health finding rule.
528
+
529
+ ## Platform Notes
530
+
531
+ ### Claude Code
532
+
533
+ Native — `Skill()` delegation, argument substitution, and the `Edit`/`Write`/`Bash` toolset work
534
+ directly. The `/sp:dev-dogfood` command is the entry point.
535
+
536
+ **Platform boundary (R3 — task 0296).** On Claude Code, `Skill()` runs **inline** in the current
537
+ session — there is no subprocess boundary, so a chained `--next` leg (refine→run, run→verify)
538
+ dispatched from the driver runs in the **same session** and is not independently observable. A
539
+ `--next` dogfood forced to follow the chain would lose per-leg provenance. Therefore a `--next`
540
+ dogfood on Claude Code ends **stop-at-testing** at the chain's testing boundary unless the operator
541
+ overrides — either by passing `--chain-follow` (the sanctioned mechanism; see
542
+ [§Arguments](#arguments) and [§`--next` chain stop-at-testing](#next-chain-stop-at-testing)) or by
543
+ **running the chained leg as its own standalone invocation**, which is exactly how the 0281 pair
544
+ completed: the dev-run dogfood stopped at testing, and `/sp:dev-verify 0281 --auto --next --force
545
+ --focus all --fix all` was driven as its own dogfood (the verify dogfood report). This is a
546
+ reporting discipline, not a bug in the chain — the chain's contract is owned by `sp:spur-dev`.
547
+
548
+ ### Codex / OpenClaw / OpenCode / Antigravity
549
+
550
+ Run the four-phase protocol via the Bash/CLI toolset; invoke this skill directly for the protocol
551
+ logic and the `spur` CLI for the `--task` sink. Parse `--json` where the testee supports it.
552
+
553
+ A session on these platforms never sees `Skill()` reference-file expansion, so the report contract
554
+ is restated here **verbatim** rather than by pointer — do not fall back to a looser ad hoc report
555
+ shape just because `report-template.md` wasn't auto-loaded.
556
+
557
+ **Always-on dual artifacts (not gated on `--save`).** Every run MUST open and maintain:
558
+
559
+ - Live: `.spur/run/dogfood/<run_id>.md`
560
+ - Report: `docs/dogfood/YYYY-MM-DD-<testee-slug>-dogfood.md`
561
+
562
+ Both start with YAML frontmatter including `status: running | aborted | complete`, `run_id`,
563
+ `protocol: sp:dogfood-testing@1.2`, and paths. Dual-write a ledger row to both files on every step
564
+ resolve. On stop, set `status` to `complete` or `aborted` (finalize-or-abort — non-skippable).
565
+
566
+ **The six mandatory section headings** (in order, each report MUST contain all six):
567
+
568
+ 1. `### 1. Testee` (include **Repro:** line)
569
+ 2. `### 2. Execution Summary` (include `#### Cost` with Method, confidence, Meter)
570
+ 3. `### 3. Monitor Ledger`
571
+ 4. `### 4. What We Did`
572
+ 5. `### 5. Issues`
573
+ 6. `### 6. Findings`
574
+
575
+ Unfinished narrative sections after abort: `⚠ incomplete — not reached` (never invent).
576
+
577
+ **The ledger requirement.** `### 3. Monitor Ledger` MUST contain the live per-step ledger table
578
+ populated on disk during Phase 2/3 as steps run, never reconstructed from memory at the end.
579
+
580
+ **Cost honesty.** Ledger totals are `~estimate` with Method + confidence LOW unless a real meter
581
+ (`ccusage` day/session, agent usage fields) is also present (then MEDIUM). If no meter:
582
+ `Meter: n/a`. Never invent billed precision.
583
+
584
+ **The footer requirement.** Every report MUST end by printing this exact block (verdict is strictly
585
+ `PASS` / `PARTIAL` / `FAIL`, grading the testee, not the surrounding task):
586
+
587
+ ```
588
+ ── Dogfood Summary ──
589
+ Result: PASS (N fixed, N unresolved, N findings)
590
+ Tokens: ~N total | ~N cached (~X% hit rate) [~estimate]
591
+
592
+ Fixed issues:
593
+ • <label> (or: (none))
594
+
595
+ Unresolved issues:
596
+ • <label> (or: (none))
597
+
598
+ Findings (P1+P2):
599
+ • P? — <label> (or: (none))
600
+
601
+ [Live: .spur/run/dogfood/<run_id>.md]
602
+ [Report: docs/dogfood/YYYY-MM-DD-<slug>-dogfood.md]
603
+ [Task: <wbs>] ← only with --task
604
+ ```
605
+
606
+ A report missing any of the six headings, the on-disk live ledger, dual paths, terminal `status`,
607
+ the Cost block, or this footer does not satisfy the dogfood contract on this platform, regardless
608
+ of `Skill()` availability.