specpro-cli 0.1.0__py3-none-any.whl

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 (76) hide show
  1. specpro_cli/__init__.py +16 -0
  2. specpro_cli/assets/commands/specpro.analyze.md +1102 -0
  3. specpro_cli/assets/commands/specpro.checklist.md +335 -0
  4. specpro_cli/assets/commands/specpro.clarify.md +581 -0
  5. specpro_cli/assets/commands/specpro.constitution.md +488 -0
  6. specpro_cli/assets/commands/specpro.feature.md +115 -0
  7. specpro_cli/assets/commands/specpro.implement.md +1881 -0
  8. specpro_cli/assets/commands/specpro.manual-test.md +206 -0
  9. specpro_cli/assets/commands/specpro.plan.md +3284 -0
  10. specpro_cli/assets/commands/specpro.qc.md +1489 -0
  11. specpro_cli/assets/commands/specpro.scenarios.md +154 -0
  12. specpro_cli/assets/commands/specpro.specify.md +1449 -0
  13. specpro_cli/assets/commands/specpro.status.md +863 -0
  14. specpro_cli/assets/commands/specpro.tasks.md +1207 -0
  15. specpro_cli/assets/commands/specpro.test-implement.md +462 -0
  16. specpro_cli/assets/commands/specpro.test-plan.md +383 -0
  17. specpro_cli/assets/commands/specpro.user-manual.md +178 -0
  18. specpro_cli/assets/scripts/bash/check-anti-coupling.sh +293 -0
  19. specpro_cli/assets/scripts/bash/check-prerequisites.sh +176 -0
  20. specpro_cli/assets/scripts/bash/common.sh +88 -0
  21. specpro_cli/assets/scripts/bash/create-new-feature.sh +336 -0
  22. specpro_cli/assets/scripts/bash/qc-auto-fix.sh +121 -0
  23. specpro_cli/assets/scripts/bash/setup-plan.sh +60 -0
  24. specpro_cli/assets/scripts/bash/verify-cumulative-records.sh +203 -0
  25. specpro_cli/assets/scripts/bash/verify-deliverables-tracked.sh +147 -0
  26. specpro_cli/assets/scripts/bash/verify-deployment.sh +239 -0
  27. specpro_cli/assets/scripts/bash/verify-frontmatter-yaml.sh +63 -0
  28. specpro_cli/assets/scripts/bash/verify-ledger.sh +376 -0
  29. specpro_cli/assets/scripts/bash/verify-shapes.sh +1082 -0
  30. specpro_cli/assets/scripts/git-hooks/pre-commit +243 -0
  31. specpro_cli/assets/scripts/install-git-hooks.sh +67 -0
  32. specpro_cli/assets/scripts/powershell/check-anti-coupling.ps1 +249 -0
  33. specpro_cli/assets/scripts/powershell/check-prerequisites.ps1 +148 -0
  34. specpro_cli/assets/scripts/powershell/common.ps1 +95 -0
  35. specpro_cli/assets/scripts/powershell/create-new-feature.ps1 +229 -0
  36. specpro_cli/assets/scripts/powershell/qc-auto-fix.ps1 +110 -0
  37. specpro_cli/assets/scripts/powershell/setup-plan.ps1 +61 -0
  38. specpro_cli/assets/scripts/powershell/verify-cumulative-records.ps1 +133 -0
  39. specpro_cli/assets/scripts/powershell/verify-deliverables-tracked.ps1 +112 -0
  40. specpro_cli/assets/scripts/powershell/verify-deployment.ps1 +278 -0
  41. specpro_cli/assets/scripts/powershell/verify-frontmatter-yaml.ps1 +56 -0
  42. specpro_cli/assets/scripts/powershell/verify-ledger.ps1 +383 -0
  43. specpro_cli/assets/scripts/powershell/verify-shapes.ps1 +978 -0
  44. specpro_cli/assets/templates/agent-context-template.md +49 -0
  45. specpro_cli/assets/templates/assumptions-template.md +248 -0
  46. specpro_cli/assets/templates/checklist-template.md +40 -0
  47. specpro_cli/assets/templates/clarifications-template.md +155 -0
  48. specpro_cli/assets/templates/constitution-template.md +50 -0
  49. specpro_cli/assets/templates/feature-spec-template.md +66 -0
  50. specpro_cli/assets/templates/plan-overview-template.md +150 -0
  51. specpro_cli/assets/templates/plan-template.md +387 -0
  52. specpro_cli/assets/templates/protocol-golden-bytes-guide.md +195 -0
  53. specpro_cli/assets/templates/requirements-template.md +356 -0
  54. specpro_cli/assets/templates/spec-template.md +267 -0
  55. specpro_cli/assets/templates/tasks-template.md +252 -0
  56. specpro_cli/assets/templates/test-tasks-template.md +174 -0
  57. specpro_cli/cli/__init__.py +5 -0
  58. specpro_cli/cli/cmd_init.py +416 -0
  59. specpro_cli/cli/cmd_remove.py +122 -0
  60. specpro_cli/cli/entry.py +181 -0
  61. specpro_cli/integrations/__init__.py +36 -0
  62. specpro_cli/integrations/base.py +601 -0
  63. specpro_cli/integrations/claude/__init__.py +101 -0
  64. specpro_cli/integrations/copilot/__init__.py +153 -0
  65. specpro_cli/integrations/cursor_agent/__init__.py +51 -0
  66. specpro_cli/integrations/gemini/__init__.py +44 -0
  67. specpro_cli/integrations/opencode/__init__.py +48 -0
  68. specpro_cli/integrations/qodercli/__init__.py +54 -0
  69. specpro_cli/integrations/registry.py +88 -0
  70. specpro_cli/packaged/__init__.py +5 -0
  71. specpro_cli/packaged/sync.py +106 -0
  72. specpro_cli-0.1.0.dist-info/METADATA +117 -0
  73. specpro_cli-0.1.0.dist-info/RECORD +76 -0
  74. specpro_cli-0.1.0.dist-info/WHEEL +4 -0
  75. specpro_cli-0.1.0.dist-info/entry_points.txt +2 -0
  76. specpro_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1449 @@
1
+ ---
2
+ description: Create or update the feature specification from a natural language feature description.
3
+ handoffs:
4
+ - label: Build Technical Plan
5
+ agent: specpro-plan
6
+ prompt: Create a plan for the spec. I am building with...
7
+ - label: Clarify Spec Requirements
8
+ agent: specpro-clarify
9
+ prompt: Clarify specification requirements
10
+ send: true
11
+ writes:
12
+ # This command's write surface: only what it produces AS THE PRODUCER of that
13
+ # (artifact, unit) pair. A write this command makes on a non-producer path is a
14
+ # boundary violation by definition (FR-051) and MUST NOT be declared here.
15
+ # The full ownership map is the UNION of every command's writes: block.
16
+ - artifact: specs/spec.md
17
+ unit: "whole file - template structure and section order preserved; plus the per-item Lifecycle fields"
18
+ - artifact: specs/assumptions.md
19
+ unit: "A0NN entries (Status / Answer / Resolution) plus the Decision Path and Summary sections"
20
+ - artifact: specs/implement_issues.md
21
+ unit: "the [specify] section -> its own entries marked [x]; the statistics table (**its own row only** — seven commands declare this artifact); appended ISS-NNN entries in any section — registration is routing; only [x]-marking is section-scoped"
22
+ ---
23
+
24
+ ## User Input
25
+
26
+ ```text
27
+ $ARGUMENTS
28
+ ```
29
+
30
+ You **MUST** consider the user input before proceeding (if not empty).
31
+
32
+ **Rerun safety — detect the artifact, default to incremental** ⚠️ [settled 2026-09-13]:
33
+
34
+ **Before writing `specs/spec.md`, detect whether it already exists.** Use the SAME check in every command:
35
+
36
+ ```bash
37
+ [ -s specs/spec.md ] && echo EXISTS || echo NEW # -s: exists AND non-empty (an empty placeholder counts as NEW)
38
+ ```
39
+
40
+ | Detection | Mode |
41
+ |-----------|------|
42
+ | **NEW** (absent or empty) | **Initial** — generate from scratch |
43
+ | **EXISTS** | **Incremental** — evolve it; **never silently regenerate from scratch** |
44
+
45
+ **Overwriting an existing artifact requires explicit, confirmed intent:**
46
+ 1. Only when the user *explicitly* asks (in their own words) does the initial path run on an existing artifact.
47
+ 2. **Even then, confirm once more before writing** — name the artifact that will be replaced and what will be lost; wait for the answer.
48
+ 3. **Silence is not consent.** An unspecified run on an existing artifact is ALWAYS incremental.
49
+
50
+ > **Why a shared rule rather than per-command courtesy**: nine of the twelve non-implementation commands already had some protection, but each wrote it its own way (`EXISTING_SPEC` check · "creates a NEW file" · `NEVER overwrite` · "incremental regeneration" · `AUTO_MODE=false`), and **three had none at all** — not by decision, but because the discipline had no shared carrier. Overwriting an artifact the user has been evolving is not recoverable within the session; the cost of asking is one prompt.
51
+
52
+
53
+ ### Scope Resolution 🆕 (FR-063 / T050 · v0.23)
54
+
55
+ 1. **作用域判定**: 当前工作目录位于 `specs/fNNN-简称/` 内 ⇒ **feature 作用域**(读写范围 = 本 feature 目录,由 `check-prerequisites.sh` 的作用域感知解析);位于仓库根或 `specs/` 根 ⇒ **母作用域**(读写母规格链)。feature 作用域内 MUST NOT 写母产物——唯一例外:**发现登记**(台账路由,`[specify]`/`[plan]` 分区)。
56
+ 2. **新会话首次执行**: 若 `specs/features.md` 存在且含 `active` 行、而用户未指明作用域 ⇒ **询问用户**在母作用域还是某个 feature 内工作,MUST NOT 自行挑选。
57
+ 3. 本命令的产物路径随之解析:feature 作用域下落 `<feature 目录>/`,母作用域下落 `specs/`。
58
+
59
+ ## Outline
60
+
61
+ **Artifact Language Rule** 🌐 [CRITICAL — applies to ALL generated content]:
62
+ - **Prose content** (descriptions, rationale, scenario text, guidance) follows the project's **Artifact Language** setting — from `specs/constitution.md` → **Artifact Language** field; default `en` when absent
63
+ - **Structural anchors are ALWAYS English**, regardless of the artifact language: section headings from the template, item ID prefixes (US/FR), status enums, and table column names — exactly as written in the template
64
+ - **Entry field labels are structural anchors too** (`source:`, `Evidence:`, `Fix Direction:`) — never translated, even when the surrounding prose is not English. They exist to be **searched**: an entry's fields must be greppable across artifacts and projects, and a translated label silently drops out of every consumer's scan.
65
+ - Rationale: fixed anchors keep artifacts machine-parseable across specpro commands and keep instructions ↔ artifacts aligned for review
66
+
67
+ The text the user typed after `/specpro-specify` in the triggering message **is** the feature description. Assume you always have it available in this conversation even if `$ARGUMENTS` appears literally below. Do not ask the user to repeat it unless they provided an empty command.
68
+
69
+ Given that feature description, do this:
70
+
71
+ 1. **Check for --review-issues argument** 🆕:
72
+
73
+ **Purpose**: Process implement issues submitted from the implement phase
74
+
75
+ a. **Parse arguments**:
76
+ - If `$ARGUMENTS` contains `--review-issues`:
77
+ * **Skip the question below**; proceed directly to step 1b (review issues)
78
+ - Else: **detect, then ask** ⚠️ [settled 2026-09-13]:
79
+ * Check the `[specify]` section of `specs/implement_issues.md` for open `[ ]` entries
80
+ * **None** → continue with normal specification generation (step 2+). **No prompt.**
81
+ * **Some** → **ask**: "N open `[specify]` issues in specs/implement_issues.md. Process them first, or run normally?"
82
+ - *Process first* → proceed to step 1b (review issues)
83
+ - *Run normally* → continue with normal specification generation (step 2+)
84
+ * **Rationale**: the flag used to be the whole switch — not passing it left pending issues **silently unprocessed**, passing it meant overriding the work the user actually wanted, and **which issues were pending was invisible until the command ran**. Detect-then-ask makes it an explicit choice; the flag now only means *"I already know — don't ask"*.
85
+ (Same model as `/specpro-implement` and `/specpro-test-plan` — see TOOL-008.)
86
+
87
+ b. **Review implement issues**:
88
+ - Read `specs/implement_issues.md`
89
+ - Extract all issues from `[specify]` section
90
+ - Filter for issues marked `[ ]` (pending) only
91
+ - If no pending issues found:
92
+ * Display: "✓ No pending [specify] issues to process"
93
+ * Exit
94
+
95
+ - Display issue summary:
96
+ ```markdown
97
+ 📋 [specify] Issues Review
98
+
99
+ Found N pending [specify] issues:
100
+ 1. [ ] ISS-XXX: Issue description
101
+ 2. [ ] ISS-XXX: Issue description
102
+ ...
103
+ ```
104
+
105
+ - For each pending issue:
106
+ * Read issue details (description, problem, suggestion)
107
+ * Determine appropriate action:
108
+ - **Add new requirement**: Insert new FR into spec.md
109
+ - **Clarify existing requirement**: Update existing FR description
110
+ - **Resolve conflict**: Modify conflicting FRs
111
+ * Apply the change to spec.md
112
+ * Mark issue as `[x]` in implement_issues.md
113
+ * Display: "✓ Processed ISS-XXX: [action taken]"
114
+
115
+ - Update the statistics table at the **top** of `implement_issues.md` (its position is deliberate — see the note below)
116
+ - **Edit order and idempotency check** ⚠️ [a silent false-skip, observed 2026-09-13]: write the **entry body first** (into its own section), then the derived summaries (statistics table + `Last Updated`) — never the reverse. A derived summary written first introduces the new ID into the file's text before the entry exists, so an idempotency guard that greps the file for that ID falsely concludes "already present" and **skips the entry**, while the summaries still claim it landed. For the same reason the guard MUST match the entry body's **line-start pattern**, never a full-text keyword search:
117
+ ```bash
118
+ grep -qE '^- \[[x ]\] ISS-<N>:' specs/implement_issues.md # correct — matches an ENTRY, not a mention
119
+ # grep -q 'ISS-<N>' … # wrong — also matches the statistics Pending-Items column, the Last Updated line, cross-references
120
+ ```
121
+ - **General rule: every grep/awk example shown in an instruction or template must itself obey the line-start pattern** (TOOL-009) — the executing side copies examples verbatim, so an example that uses a whole-file match propagates the same misjudgment to everyone who copies it. This file has already corrected its own sentinel self-check command under this rule.
122
+ `.specpro/scripts/bash/verify-ledger.sh` reports the resulting inconsistency as a count mismatch — but only if it is run, and by then the entry is already missing.
123
+ - **Entry placement**: append new entries to the end of their own section, never to the end of the file. The file's statistics block sits at the top precisely so that "append to the end" lands inside the last section rather than between sections; moving or duplicating a section header breaks that and produces an orphaned section no `--review-issues` run will read.
124
+ - **Verify mechanically after writing**: run `.specpro/scripts/bash/verify-ledger.sh` — it checks entry section membership, statistics-vs-actual counts, and the trailing newline in one pass (non-zero exit names the violation). Marking issues `[x]` changes the counts, so this applies to this command too, not only to commands that append. A pre-commit hook enforces the same check.
125
+
126
+ c. **Run quality validation on updated spec** 🆕:
127
+ ```bash
128
+ echo ""
129
+ echo "📋 Running quality validation on updated spec.md..."
130
+ echo " Validating against the checklist's quality criteria..."
131
+ echo " QC rebuilds the checklist and queues every non-passing item for THIS command."
132
+ echo ""
133
+
134
+ # ⚠️ **No `--auto`, no authorisation parameter** (2026-09-19 ruling, FR-058).
135
+ # This command used to delegate the REPAIR to `/specpro-qc` and call it a
136
+ # quality gate. ⚠️ That made the judge the repairer, and it is why the caller
137
+ # had to say which artifact it owned — a parameter that existed only to make a
138
+ # boundary violation declareable. **The repair is this command's own job**, and
139
+ # the check's job is to produce the list of what needs repairing.
140
+ # ⚠️ **The loop closes here, and it is short on purpose**: qc queues its
141
+ # non-passing items into the `[specify]` section — **the very section this
142
+ # command consumes** — so the fix path is "read the queue, fix the spec,
143
+ # re-run the check", not "hope the checker also repairs".
144
+ /specpro-qc --scope="incremental"
145
+
146
+ QC_EXIT_CODE=$?
147
+
148
+ if [[ $QC_EXIT_CODE -eq 0 ]]; then
149
+ echo ""
150
+ echo "✅ Quality validation PASSED"
151
+ echo " All quality criteria met."
152
+ echo " specs/checklists/requirements.md rebuilt for this run"
153
+ else
154
+ echo ""
155
+ echo "❌ Quality validation FAILED"
156
+ echo " One or more criteria did not pass. **The non-passing ones are now"
157
+ echo " entries in the [specify] queue** (FR-059) — that is this command's"
158
+ echo " own queue, so they are fixed HERE, by the spec's producer."
159
+ echo ""
160
+ echo "Check specs/checklists/requirements.md for the per-item verdicts."
161
+ echo "Then process the queued entries with --review-issues."
162
+ exit 1
163
+ fi
164
+ ```
165
+
166
+ d. **Display completion summary**:
167
+ ```markdown
168
+ ✅ Completed [specify] issues review and quality validation
169
+
170
+ Processed: N issues
171
+ Updated: specs/spec.md
172
+ Validated: Quality check passed — no criterion failed (`FR-061`)
173
+ Marked as [x] in implement_issues.md
174
+
175
+ ⚠️ IMPORTANT: Next steps
176
+
177
+ 1. Run /specpro-plan to update technical design
178
+ 2. Run /specpro-tasks to update task list
179
+ 3. Then you can process [plan] or [tasks] issues
180
+
181
+ Do NOT process [plan] or [tasks] issues yet.
182
+ They require the plan/tasks update first.
183
+ ```
184
+ 2. **Pre-flight Checks** ✨ (Fast-fail validation before core logic):
185
+
186
+ **Purpose**: Verify environment and prerequisites before executing specification generation
187
+
188
+ a. **Required files check**:
189
+ ```bash
190
+ CONSTITUTION="specs/constitution.md"
191
+ SPEC_TEMPLATE=".specpro/templates/spec-template.md"
192
+ ASSUMP_TEMPLATE=".specpro/templates/assumptions-template.md"
193
+
194
+ if [[ ! -f "$CONSTITUTION" ]]; then
195
+ echo "❌ ERROR: Constitution not found at $CONSTITUTION"
196
+ echo "Please run /specpro-constitution to create the project constitution first."
197
+ exit 1
198
+ fi
199
+
200
+ if [[ ! -f "$SPEC_TEMPLATE" ]]; then
201
+ echo "❌ ERROR: Spec template not found at $SPEC_TEMPLATE"
202
+ exit 1
203
+ fi
204
+
205
+ if [[ ! -f "$ASSUMP_TEMPLATE" ]]; then
206
+ echo "❌ ERROR: Assumptions template not found at $ASSUMP_TEMPLATE"
207
+ exit 1
208
+ fi
209
+ ```
210
+
211
+ b. **Directory permissions check**:
212
+ ```bash
213
+ # After running create-new-feature.sh to get FEATURE_DIR
214
+ if [[ ! -d "$FEATURE_DIR" ]]; then
215
+ echo "❌ ERROR: Feature directory not writable: $FEATURE_DIR"
216
+ exit 1
217
+ fi
218
+
219
+ # Test write permission
220
+ touch "$FEATURE_DIR/.test_write" 2>/dev/null || {
221
+ echo "❌ ERROR: Cannot write to $FEATURE_DIR"
222
+ exit 1
223
+ }
224
+ rm -f "$FEATURE_DIR/.test_write"
225
+ ```
226
+
227
+ c. **Constitution validation**:
228
+ ```bash
229
+ # Verify Constitution is not empty
230
+ CONSTITUTION_SIZE=$(wc -c < "$CONSTITUTION")
231
+ if [[ $CONSTITUTION_SIZE -lt 100 ]]; then
232
+ echo "⚠️ WARNING: Constitution appears to be empty or very small"
233
+ echo "Please verify specs/constitution.md has content"
234
+ fi
235
+
236
+ # Count principles/articles
237
+ PRINCIPLE_COUNT=$(grep -c "^##\|^###\|^#" "$CONSTITUTION" 2>/dev/null || true)
238
+ : "${PRINCIPLE_COUNT:=0}"
239
+ if [[ $PRINCIPLE_COUNT -lt 2 ]]; then
240
+ echo "⚠️ WARNING: Constitution has fewer than 2 sections"
241
+ echo "Consider adding more principles before proceeding"
242
+ fi
243
+ ```
244
+
245
+ d. **Report check completion**:
246
+ ```markdown
247
+ ✓ Pre-flight checks passed
248
+ - Constitution: ✅ ($PRINCIPLE_COUNT sections)
249
+ - Templates: ✅ (spec, assumptions)
250
+ - Permissions: ✅ (writable)
251
+ ```
252
+
253
+ **Fast-fail**: If any check fails, abort immediately with clear error message
254
+
255
+ 1. **Generate a concise short name** (2-4 words) for tracking:
256
+ - Analyze the feature description and extract the most meaningful keywords
257
+ - Create a 2-4 word short name that captures the essence of the feature
258
+ - Use action-noun format when possible (e.g., "user-auth", "plugin-architecture")
259
+ - Preserve technical terms and acronyms (OAuth2, API, JWT, protocol acronyms)
260
+ - Keep it concise but descriptive enough to understand the feature at a glance
261
+
262
+ 2. **Check existing specification and determine operation mode**:
263
+
264
+ a. **Check if spec.md exists**:
265
+ ```bash
266
+ SPEC_FILE="specs/spec.md"
267
+
268
+ if [[ -f "$SPEC_FILE" ]]; then
269
+ EXISTING_SPEC=true
270
+ # Read existing spec to gather statistics
271
+ # ⚠️ **All three of the old patterns were anchored on forms the template never
272
+ # emits** (T094/ISS-63) — measured on a spec built from `spec-template.md`:
273
+ # US 0 ≠ 11 · FR 0 ≠ 57. The User-Story heading is `### US1 - …`; the FR line is an
274
+ # INDENTED bold list item (` - **FR-XXX**: …`), so a line-start anchor `^- ` misses
275
+ # every one of them. Both now use the same patterns as `status.md` — that file
276
+ # documents this format contract in a comment and MUST stay consistent with `qc`.
277
+ US_COUNT=$(grep -cE '^### US[0-9]+ ' "$SPEC_FILE" 2>/dev/null || true)
278
+ FR_COUNT=$(grep -cE '^[[:space:]]*- \*\*FR-[0-9]+[A-E]?\*\*:' "$SPEC_FILE" 2>/dev/null || true)
279
+ : "${US_COUNT:=0}"
280
+ : "${FR_COUNT:=0}"
281
+ # ⚠️ A third counter, `ASSUMP_COUNT`, used to sit here. It is **removed, not
282
+ # fixed**: (a) its pattern (`^### **[A-`) matched nothing, (b) it scanned
283
+ # `$SPEC_FILE` while assumptions live in `specpro.assumptions.md` — the wrong
284
+ # artifact — and (c) it was **never read** by anything (not in the statistics
285
+ # display below). A wrong predicate inside a value nobody reads is pure liability
286
+ # (the shape this project keeps finding: 写了却从未被调用的东西).
287
+
288
+ # Extract current version
289
+ CURRENT_VERSION=$(grep "^**Version**:" "$SPEC_FILE" | head -1 | awk '{print $2}')
290
+ else
291
+ EXISTING_SPEC=false
292
+ fi
293
+ ```
294
+
295
+ b. **Determine operation mode**:
296
+
297
+ **If NO existing spec** (`$EXISTING_SPEC = false`):
298
+ - This is **initial specification**
299
+ - Set `UPDATE_MODE=false`
300
+ - Set `SPEC_VERSION="0.1"`
301
+ - Run script: `.specpro/scripts/bash/create-new-feature.sh --json "$ARGUMENTS"`
302
+ - Proceed to step 3 (load Constitution, generate spec)
303
+
304
+ **If existing spec EXISTS** (`$EXISTING_SPEC = true`):
305
+ - This is an **evolution iteration**
306
+ - Ask user for intent:
307
+ ```markdown
308
+ ## Existing Specification Detected
309
+
310
+ You already have a specification for this application:
311
+
312
+ **Current Spec**: Version $CURRENT_VERSION
313
+ **Statistics**:
314
+ - User Stories: $US_COUNT
315
+ - Functional Requirements: $FR_COUNT
316
+
317
+ **Your Input**: "$ARGUMENTS"
318
+
319
+ **What do you want to do?**
320
+
321
+ 1. **UPDATE** existing spec (evolve the application)
322
+ - Keep all existing content
323
+ - Add new features/requirements
324
+ - Update existing sections if specified
325
+ - Preserve validated constraints
326
+ - Generate Change Summary with [create]/[update]/[deprecated] tags (changed items only — unchanged items are not logged)
327
+ - Auto-commit to preserve history
328
+
329
+ 2. **VIEW** current spec first
330
+ - Display summary of current specification
331
+ - Show User Stories, Requirements, Constraints
332
+ - Then ask again
333
+
334
+ Your choice (1/2):
335
+ ```
336
+
337
+ - **If user chooses 1 (UPDATE)**:
338
+ - Set `UPDATE_MODE=true`
339
+ - Parse current version (e.g., "0.1")
340
+ - Increment version: `NEW_VERSION=$(echo "0.1" | awk -F. '{print $1"."$2+1}')`
341
+ - Set `SPEC_VERSION=$NEW_VERSION`
342
+ - Run script to get SPEC_FILE path: `.specpro/scripts/bash/create-new-feature.sh --json "$ARGUMENTS"`
343
+ - Proceed to step 3 with merge logic
344
+
345
+ - **If user chooses 2 (VIEW)**:
346
+ - Display current spec summary:
347
+ ```markdown
348
+ ## Current Specification Summary
349
+
350
+ ### User Stories ($US_COUNT total)
351
+ [List first 10 stories with priorities]
352
+
353
+ ### Key Functional Requirements
354
+ [List key requirements]
355
+
356
+ ### Constitution Constraints
357
+ [List key constraints]
358
+ ```
359
+ - Ask again for choice 1/2
360
+
361
+ 2.5. **Dynamic assumption resolution** (for initial specification only):
362
+
363
+ **Purpose**: Identify and resolve CRITICAL architectural assumptions that MUST be clarified BEFORE spec generation. Unlike clarifications (which improve spec quality post-generation), these assumptions block spec generation because they fundamentally affect the architecture and direction.
364
+
365
+ **This step ONLY applies to UPDATE_MODE=false (initial specification)**. Skip this step if UPDATE_MODE=true.
366
+
367
+ a. **Initial analysis of user input**:
368
+ - Analyze the user's feature description for CRITICAL architectural decisions
369
+ - Identify decisions that affect: architecture, scope, platform, deployment, data model
370
+ - Ask: "What is the MOST CRITICAL unresolved decision without which we cannot proceed?"
371
+ - Examples of critical decisions:
372
+ * "Notepad" → Local vs Web? (affects architecture, data model, deployment)
373
+ * "Chat app" → Real-time vs Async? (affects protocol, infrastructure)
374
+ * "Multi-user" → Single-device vs Collaborative? (affects sync, backend)
375
+ * "High performance" → What's the target scale? (affects architecture choices)
376
+ - Load `.specpro/templates/assumptions-template.md` to understand the required format
377
+
378
+ b. **Generate first-level assumptions** (if any):
379
+ - If CRITICAL assumptions are identified:
380
+ 1. Create `specs/assumptions.md` using the template
381
+ 2. Add 1-3 initial assumptions to the file
382
+ 3. For each assumption, include:
383
+ - Status: [ ] Pending
384
+ - Context: What led to this question (user input)
385
+ - Impact: What this affects (architecture, scope, platform, etc.)
386
+ - Question: Clear, specific question
387
+ - Options: 2-4 mutually exclusive options with implications
388
+ - Recommended: Best option based on context with reasoning
389
+ 4. Display blocking message:
390
+ ```markdown
391
+ ## 🔑 Critical Assumptions Detected
392
+
393
+ Before I can generate the specification, I need to clarify these CRITICAL decisions
394
+ that affect the architecture and direction of the feature:
395
+
396
+ **Assumptions File**: specs/assumptions.md
397
+ - Total: N critical assumptions
398
+
399
+ These MUST be resolved before spec generation can proceed.
400
+
401
+ Let's resolve them one by one...
402
+ ```
403
+ - If NO critical assumptions are identified (user input is clear):
404
+ - Skip assumption resolution
405
+ - Proceed directly to Step 3 (Load Constitution)
406
+ - Note: "No critical assumptions detected. User input is sufficiently clear to proceed."
407
+
408
+ c. **Interactive resolution loop** ✨ ENHANCED with progress tracking:
409
+
410
+ **WHILE** there are pending assumptions (status `[ ]`):
411
+
412
+ 1. **Present ONE current assumption**:
413
+ - Display assumption with:
414
+ - Progress indicator: "### Question [current]/[total]: [ID]"
415
+ - ID, Question, Context, Impact
416
+ - Options table (if applicable)
417
+ - Recommended option with reasoning
418
+ - Format:
419
+ ```markdown
420
+ ### Question [ID]: [Question Summary]
421
+
422
+ **Context**: [What led to this question]
423
+
424
+ **Impact**: [What this affects]
425
+
426
+ **Question**:
427
+ [Full question text]
428
+
429
+ **Options** (if applicable):
430
+ | Option | Description | Implications |
431
+ |--------|-------------|--------------|
432
+ | A | [Option A] | [Implications] |
433
+ | B | [Option B] | [Implications] |
434
+ | C | [Option C] | [Implications] |
435
+
436
+ **Recommended**: Option [X] - [Reasoning]
437
+
438
+ Your answer (option letter or custom):
439
+ ```
440
+
441
+ 2. **Wait for user response**
442
+ - Accept: option letter (A/B/C), "yes"/"recommended" for recommendation, or custom answer
443
+ - Validate response maps to options or is appropriate
444
+
445
+ 3. **Update assumptions.md immediately**:
446
+ - Mark assumption as `[x]` Resolved
447
+ - Fill in "Answer" field with user's response
448
+ - Fill in "Resolution" field with:
449
+ - How this answer guides spec generation
450
+ - Related architectural decisions
451
+ - Next assumptions that may emerge (see step 3d)
452
+ - Save file (atomic write)
453
+ - Display progress: "✓ Resolved [current]/[total] assumptions"
454
+
455
+ 4. **Contextual re-analysis** (KEY STEP):
456
+ - Based on ALL previous answers + user input
457
+ - Ask: "Based on this answer, what's the NEXT critical decision?"
458
+ - Identify NEW assumptions that emerge:
459
+ * Check if previous decisions reveal new critical questions
460
+ * Check if decisions eliminate previously planned questions
461
+ - Generate next assumption (if any):
462
+ * Add to assumptions.md with updated context
463
+ * Include "Context": Previous decisions that led to this
464
+ * Mark as `[ ]` Pending
465
+ - If NO new assumptions emerge:
466
+ * Continue loop (there may be other pending assumptions)
467
+
468
+ 5. **Check loop condition**:
469
+ - If there are still pending assumptions → Continue to next iteration (back to step c.1)
470
+ - If ALL assumptions resolved → Exit loop
471
+
472
+ d. **Completion of assumption resolution**:
473
+
474
+ 1. **Display summary**:
475
+ ```markdown
476
+ ✓ All critical assumptions resolved
477
+
478
+ **Total Assumptions Resolved**: N
479
+ **Assumptions File**: specs/assumptions.md
480
+
481
+ **Decision Path**:
482
+ - A001: [Answer] → [Impact]
483
+ - A002: [Answer] → [Impact] (emerged after A001)
484
+ - A003: [Answer] → [Impact] (emerged after A001, A002)
485
+
486
+ **Architectural Direction**:
487
+ - [Summary of decisions]
488
+ - [Key implications for spec generation]
489
+
490
+ Proceeding with spec generation based on these decisions...
491
+ ```
492
+
493
+ 2. **Update assumptions.md**:
494
+ - Add "Decision Path" section showing complete decision history
495
+ - Add "Summary" section with totals
496
+ - Update "Status": Resolved
497
+ - Mark "Ready for Spec Generation": YES
498
+
499
+ 3. **Store context for spec generation**:
500
+ - Keep all resolved assumptions accessible
501
+ - Use these decisions to guide Step 5 (specification generation)
502
+ - Reference when generating FRs, User Stories, architecture decisions
503
+
504
+ e. **Skip assumption resolution** (if UPDATE_MODE=true or no critical assumptions):
505
+ - This step is skipped for UPDATE_MODE=true (updating existing spec)
506
+ - For initial specs with no critical assumptions, skip and proceed
507
+ - Note: Existing specs should have already resolved assumptions during initial creation
508
+
509
+ 3. **Load Constitution and identify applicable principles** ✨ ENHANCED with incremental caching:
510
+
511
+ **Purpose**: Ensure the feature specification complies with project principles defined in the Constitution, regardless of Constitution structure or version.
512
+
513
+ a. **Detect operation mode** ✨ NEW:
514
+ ```bash
515
+ CACHE_FILE=".specpro/cache/constitution-matching.md"
516
+
517
+ # ⚠️ **The cache is keyed on the CONSTITUTION's CONTENT, not on the file's existence**
518
+ # (`T236` / `ISS-209`). The constitution is **amended** — its `**Version**` /
519
+ # `**Last Amended**` move — and a hit keyed on nothing would then serve a principle set
520
+ # that no longer holds, **silently**, because the steps that would have re-derived it are
521
+ # the ones being skipped. The key is what makes reuse safe: a moved constitution is a MISS.
522
+ # `shasum` (macOS/BSD) and `sha256sum` (GNU) — the repository's usual portability pair.
523
+ CONSTITUTION_HASH=$( (shasum -a 256 specs/constitution.md 2>/dev/null \
524
+ || sha256sum specs/constitution.md 2>/dev/null) | cut -d' ' -f1)
525
+
526
+ if [[ "$UPDATE_MODE" = "false" ]]; then
527
+ # Initial spec: Full Constitution matching
528
+ CACHE_MODE="generate"
529
+ elif [[ -n "$CONSTITUTION_HASH" ]] && [ -f "$CACHE_FILE" ] \
530
+ && grep -qF "**Constitution Hash**: $CONSTITUTION_HASH" "$CACHE_FILE"; then
531
+ # Hit AND the constitution is unchanged since the cache was written.
532
+ CACHE_MODE="reuse"
533
+ else
534
+ # Absent — or written against a constitution that has since moved ⇒ regenerate.
535
+ CACHE_MODE="generate"
536
+ fi
537
+ ```
538
+
539
+ a2. **On a cache HIT, the matching is already done — read it, do not re-derive** ⚠️:
540
+ ```bash
541
+ if [[ "$CACHE_MODE" = "reuse" ]]; then
542
+ echo "✓ Reusing Constitution matching from cache (constitution unchanged: ${CONSTITUTION_HASH:0:12})"
543
+ cat "$CACHE_FILE"
544
+ fi
545
+ ```
546
+
547
+ ⇒ **When `CACHE_MODE=reuse`, SKIP steps b through f.** The matched domains, principles and
548
+ constraints are exactly what the cache holds, so re-deriving them is the work the cache
549
+ exists to avoid. Continue at `g`, which on a reuse leaves the file untouched.
550
+
551
+ ⚠️ **Before this step existed, `CACHE_MODE` was written and never read** (`T236` / `ISS-209`):
552
+ `g` decided only *whether to write*, so a hit could not change any behaviour, and the
553
+ `✓ Reusing Constitution matching from cache` line was the mechanism's only consumer. A cache
554
+ nothing reads is not a cache — it is a file that grows and a branch nothing takes. ⚠️ **The
555
+ repo names this shape directly** (`CLAUDE.md` → 「改机制前先核验它是否接在执行链上」: "写了却从未被调用的缓存").
556
+
557
+ b. **Read Constitution**:
558
+ - Load `specs/constitution.md`
559
+ - Parse ALL principles, requirements, and governance rules
560
+ - Do NOT assume any specific structure (Articles, Sections, etc.)
561
+ - Store for domain-based matching
562
+
563
+ c. **Identify feature domains** from the user's feature description:
564
+ - Analyze the user's input description for key terms
565
+ - Map to feature domains using these keyword patterns:
566
+
567
+ | Domain | Trigger Keywords | Constitution Search Terms |
568
+ |--------|-----------------|---------------------------|
569
+ | **Network/Connectivity** | connect, network, socket, remote, server, client, tcp, udp | network, async, blocking, I/O, performance, concurrent, connection |
570
+ | **Multiplatform** | Android, iOS, Desktop, cross-platform, platform, shared | multiplatform, platform, shared module, common, expect, actual |
571
+ | **Security/Privacy** | password, authentication, encrypt, credentials, token, secret, oauth, login | security, privacy, encryption, credential, logging, sensitive, secure |
572
+ | **Protocol/Codec** | encoding, decoding, protocol, codec, format, parse, serialize, compress | protocol, test, coverage, risk, high-risk, test-first, encoding, decoding |
573
+ | **UI/UX** | interface, display, render, screen, view, component, widget, button, dialog | UI, interface, user, experience, low-risk, interface component |
574
+ | **Data/Persistence** | database, storage, save, load, persist, cache, file, record | data, persistence, storage, database, serialization |
575
+ | **Performance** | speed, latency, throughput, concurrent, optimize, fast, slow | performance, resource, latency, throughput, optimization |
576
+
577
+ c. **Match feature domains to Constitution principles** (keyword-based, NOT article-number-based):
578
+ - For each identified domain, search Constitution content for related principles:
579
+ - Use the "Constitution Search Terms" from the table above
580
+ - Search in principle titles, requirement text, and governance sections
581
+ - Do NOT rely on article numbers or section names
582
+ - Example matching logic:
583
+ ```
584
+ If "Network/Connectivity" domain detected:
585
+ Search for principles containing: "network", "async", "blocking", "I/O", "performance"
586
+ Match might be: "Article V: Performance & Resource Management"
587
+ OR: "Section 3: Network Operations"
588
+ OR: Any principle with "network I/O MUST use async patterns"
589
+
590
+ If "Protocol/Codec" domain detected:
591
+ Search for principles containing: "protocol", "test", "coverage", "risk", "high-risk"
592
+ Match might be: "Article IV: Risk-Based Quality Assurance"
593
+ OR: "Section: Testing Requirements"
594
+ OR: Any principle with "Protocol implementations require Test-First"
595
+ ```
596
+
597
+ d. **Extract matched principle requirements**:
598
+ - For each matched principle, extract:
599
+ - Principle title/heading
600
+ - Specific MUST/SHOULD requirements
601
+ - Risk level (if defined, e.g., "High-Risk Module")
602
+ - Testing requirements (if defined, e.g., "Test-First MANDATORY")
603
+ - Create a constraint summary for spec.md
604
+
605
+ e. **Generate Constitution Constraints section** (to be inserted into spec.md):
606
+ - Format matched principles as constraints:
607
+ ```markdown
608
+ ## Constitution Constraints
609
+
610
+ This feature must comply with the following principles from the project Constitution:
611
+
612
+ ### [Principle Title]
613
+ - **Requirement**: [Specific MUST/SHOULD statement from Constitution]
614
+ - **Source**: Constitution - [Principle Section]
615
+ - **Risk Level**: [If defined, e.g., "High-Risk Module (Network Transport)"]
616
+ - **Implications**: [What this means for the feature]
617
+
618
+ ### [Another Principle Title]
619
+ - **Requirement**: [Specific requirement from Constitution]
620
+ - **Source**: Constitution - [Principle Section]
621
+ - **Risk Level**: [If defined]
622
+ - **Implications**: [What this means for the feature]
623
+ ```
624
+ - If NO principles match the feature domains, document this:
625
+ ```markdown
626
+ ## Constitution Constraints
627
+
628
+ No specific Constitution principles were identified as applicable to this feature based on the domain analysis.
629
+ ```
630
+
631
+ f. **Apply constraints to Functional Requirements** (during step 5.c generation):
632
+ - When generating functional requirements, incorporate Constitution constraints
633
+ - Example: If Constitution requires "Network I/O MUST use async patterns" and feature involves "connect to server":
634
+ - FR-xxx: System MUST connect to the server using non-blocking async I/O (per Constitution)
635
+
636
+ g. **Cache Constitution matching results** ✨ NEW:
637
+ ```bash
638
+ CACHE_FILE=".specpro/cache/constitution-matching.md"
639
+ CACHE_DIR=".specpro/cache"
640
+
641
+ # Create cache directory if not exists
642
+ mkdir -p "$CACHE_DIR"
643
+
644
+ # If CACHE_MODE=generate, save matching results
645
+ # ⚠️ On `reuse` this block is SKIPPED — rewriting an unchanged cache would be churn, and
646
+ # the hash it carries is what `a` will key on next time (`T236` / `ISS-209`).
647
+ if [[ "$CACHE_MODE" = "generate" ]]; then
648
+ cat > "$CACHE_FILE" <<EOF
649
+ # Constitution Matching Cache
650
+
651
+ **Feature**: [FEATURE_NAME]
652
+ **Generated**: [DATE]
653
+ **Spec Version**: [VERSION]
654
+ **Constitution Hash**: $CONSTITUTION_HASH
655
+
656
+ ## Matched Domains
657
+ [List of domains detected]
658
+
659
+ ## Matched Principles
660
+ [List of matched Constitution principles with constraints]
661
+
662
+ ## Last Modified
663
+ [TIMESTAMP]
664
+ EOF
665
+ echo "✓ Constitution matching cached to $CACHE_FILE"
666
+ else
667
+ echo "✓ Reusing Constitution matching from cache"
668
+ fi
669
+ ```
670
+
671
+ 4. Load `.specpro/templates/spec-template.md` to understand required sections.
672
+
673
+ 5. **Generate or update specification** ✨ ENHANCED with progress tracking:
674
+
675
+ **If UPDATE_MODE=false** (initial specification):
676
+
677
+ a. **Parse user description from Input** 📋 [1/6]
678
+ b. **Extract key concepts** 📋 [2/6]
679
+ c. **Generate specification based on resolved assumptions** 📋 [3/6]:
680
+ - Load `specs/assumptions.md` (if exists, created in Step 2.5)
681
+ - Use resolved assumptions to guide:
682
+ * Architecture decisions
683
+ * Platform choices (e.g., local vs web, desktop vs mobile)
684
+ * Scope boundaries
685
+ * Feature priorities
686
+ * Technology direction
687
+ - For remaining unclear aspects (non-critical):
688
+ * Make informed guesses based on:
689
+ - Constitution principles
690
+ - Context from resolved assumptions
691
+ - Industry standards
692
+ - Common patterns
693
+ * Convert ALL assumptions (both resolved and inferred) into Functional Requirements
694
+ * Examples:
695
+ - Instead of "Assume LAN <10ms", write "System MUST operate in LAN environments with <10ms latency"
696
+ - Instead of "Assume 8GB RAM", write "System MUST support teacher devices with 8GB RAM minimum"
697
+ * DO NOT use [NEEDS CLARIFICATION] markers - all ambiguity detection is deferred to /specpro-clarify --scan
698
+ d. **Fill User Scenarios & Testing** 📋 [4/6]:
699
+ - Generate user stories with format:
700
+ ```markdown
701
+ ### US[ID] - [Title] (Priority: PX)
702
+
703
+ **Lifecycle**: [specify:create][plan:create][tasks:create]
704
+
705
+ [Description]
706
+
707
+ **Why this priority**: [Rationale]
708
+
709
+ **Independent Test**: [Test strategy]
710
+
711
+ **Acceptance Scenarios**:
712
+ 1. Given...When...Then...
713
+ ```
714
+ - Each new user story gets Lifecycle field: `[specify:create][plan:create][tasks:create]`
715
+
716
+ e. **Generate Functional Requirements** 📋 [5/5]:
717
+ - Generate FRs grouped by User Story with format:
718
+ ```markdown
719
+ #### [User Story Title] (US[ID])
720
+
721
+ - **FR-XXX**: [Requirement Title]
722
+ **Lifecycle**: [specify:create][plan:create][tasks:create]
723
+ System MUST [requirement].
724
+
725
+ - **FR-XXX**: [Requirement Title]
726
+ **Lifecycle**: [specify:create][plan:create][tasks:create]
727
+ System MUST [requirement].
728
+ ```
729
+ - Each new FR gets Lifecycle field: `[specify:create][plan:create][tasks:create]`
730
+ - Group FRs by their associated User Story for clear traceability
731
+
732
+ f. **Generate Change Summary** (for initial spec):
733
+ ```markdown
734
+ ## Change Summary
735
+
736
+ **Version**: 0.1
737
+ **Update Type**: Initial
738
+ **Changes Overview**:
739
+ - **Added**: Initial specification with N User Stories, M Requirements
740
+ ```
741
+
742
+ g. **Return**: SUCCESS (spec ready for planning)
743
+
744
+ **If UPDATE_MODE=true** (update existing specification):
745
+
746
+ a. **Parse existing spec.md** 📋 [1/5]:
747
+ - Extract ALL User Stories with:
748
+ - ID (US1, US2, etc.)
749
+ - Title
750
+ - Priority (P1, P2, P3)
751
+ - Acceptance Criteria
752
+ - **Lifecycle**: [specify:<status>][plan:<status>][tasks:<status>]
753
+ - Extract ALL Functional Requirements
754
+ - ID (FR-xxx, FR-yyy, etc.)
755
+ - Title
756
+ - **Lifecycle**: [specify:<status>][plan:<status>][tasks:<status>]
757
+ - Extract ALL Constitution Constraints
758
+
759
+ b. **Analyze user input for changes** 📋 [2/5]:
760
+ - Identify **new features** to add (not in existing spec)
761
+ - Identify **modifications** to existing features
762
+ - Identify **deprecations** (features to mark as deprecated)
763
+
764
+ c. **Detect architectural conflicts** 📋 [3/5]:
765
+ - Load existing spec.md and extract critical architectural decisions:
766
+ * Application type: Local vs Web vs Hybrid
767
+ * Platform scope: Desktop vs Mobile vs Cross-platform
768
+ * Deployment model: Single-tenant vs Multi-tenant
769
+ * Data storage: Local vs Cloud vs Hybrid
770
+ * Collaboration model: Single-user vs Multi-user vs Real-time collaborative
771
+ * Performance model: Batch vs Real-time vs Stream processing
772
+ - Compare user's new input ($ARGUMENTS) against existing architectural decisions
773
+ - Detect **architectural conflicts** that would invalidate large portions of existing spec:
774
+ * **Local → Web** OR **Web → Local**: Completely different architecture, data model, deployment
775
+ * **Single-user → Collaborative**: Requires sync, conflict resolution, backend
776
+ * **Desktop → Mobile** OR **Mobile → Desktop**: Platform-specific changes, UI framework
777
+ * **Single-platform → Cross-platform**: Requires significant refactoring
778
+ * **Online → Offline** OR **Offline → Online**: Major architectural shift
779
+ - If architectural conflicts detected:
780
+ 1. List specific conflicts identified
781
+ 2. Calculate estimated impact (percentage of FRs that would be deprecated)
782
+ 3. Display **RESTART recommended** message:
783
+ ```markdown
784
+ ## ⚠️ Architectural Conflict Detected
785
+
786
+ Your new input conflicts with the current architectural direction:
787
+
788
+ **Current Spec**: Version $CURRENT_VERSION
789
+ **Current Architecture**: [Summary of current architecture]
790
+
791
+ **Your Input**: "$ARGUMENTS"
792
+
793
+ **Conflicts Identified**:
794
+ - [Conflict 1]: [Current] → [Requested] (Impact: [X]% of FRs deprecated)
795
+ - [Conflict 2]: [Current] → [Requested] (Impact: [Y]% of FRs deprecated)
796
+ ...
797
+
798
+ **Estimated Impact**:
799
+ - Approximately Z% of existing Functional Requirements would be deprecated
800
+ - Major architectural changes required
801
+
802
+ **Recommendations**:
803
+ 1. **RESTART** (Recommended) - Start fresh with new architectural direction
804
+ - Clean slate, no deprecated baggage
805
+ - Version reset to 0.1
806
+ - Current spec preserved in Git history
807
+
808
+ 2. **UPDATE** - Continue with evolution (will deprecate conflicting items)
809
+ - Many existing FRs marked as [deprecated]
810
+ - Change Summary will show extensive deprecations
811
+ - Version incremented to $NEW_VERSION
812
+
813
+ Your choice (1/2):
814
+ ```
815
+ 4. If user chooses 1 (RESTART):
816
+ - Ask for confirmation: "⚠️ Are you sure? This will DELETE the current spec.md and start fresh. Type 'RESTART' to confirm:"
817
+ - If confirmed:
818
+ * Delete existing spec.md
819
+ * Set `UPDATE_MODE=false`
820
+ * Set `SPEC_VERSION="0.1"` (reset to initial)
821
+ * Proceed to Step 2.5 (Dynamic Assumption Resolution) as if initial spec
822
+ - Else:
823
+ * Return to choice 1/2
824
+ 5. If user chooses 2 (UPDATE):
825
+ * Set `UPDATE_MODE=true`
826
+ * Proceed to Step 5.d with extensive deprecations
827
+ * Note: User has been warned about impact
828
+
829
+ - If NO architectural conflicts:
830
+ * Proceed to Step 5.d (normal update flow)
831
+
832
+ d. **Generate Change Summary** 📋 [4/5] (if no conflicts or user chose UPDATE):
833
+ - Count changes:
834
+ - Added: N new items
835
+ - Modified: X items
836
+ - Deprecated: Y items
837
+ - Determine update type:
838
+ - Feature Addition: Added features without breaking changes
839
+ - Refactor: Restructured existing functionality
840
+ - Breaking Change: Incompatible changes
841
+ - Bug Fix: Fixed issues
842
+ - ⚠️ **不要产出逐项变更表**(`T239` / `ISS-212`):模板里那个 `### Detailed Changes` 块**已删除**,因为它**没有任何消费者**、且与每项的 `**Lifecycle**:` 字段和 `### Changes Overview` **复述同一事实**。要逐项细节,读**该项自己的 Lifecycle 字段**。
843
+
844
+ e. **Merge and generate updated spec.md** 📋 [5/5]:
845
+
846
+ **Lifecycle Update Rules**:
847
+
848
+ **For ALL items that CARRY a Lifecycle — which is User Stories and Functional Requirements, and nothing else** ⚠️ (`T239` / `ISS-212`):
849
+ ⚠️ **`## Constitution Constraints` is NOT in this scope, and that is an adjudication, not an omission.** Evidence: ① `templates/spec-template.md`'s `## Constitution Constraints` section is `[Add constitution constraints if any]` — it **emits no `**Lifecycle**:` field**; ② the plan-layer reader (`commands/specpro.plan.md` → `4.a`) enumerates **two** classes (US, FR), not three; ③ measured on `specs/spec.md`: **73** `**Lifecycle**:` lines = 11 US + 62 FR — **zero** belong to a Constitution Constraint. ⇒ A rule written for a class that cannot carry the field is a rule nothing can follow; **this line used to name three**. ⚠️ **Do not "fix" it by adding Lifecycle fields to that section**: nothing reads them (no command parses a constraint's lifecycle), so the field would be a value with no consumer — and the section is a *reference* to the constitution, not a tracked requirement.
850
+
851
+ a. **New items** (not in existing spec):
852
+ - Add to spec with Lifecycle:
853
+ ```markdown
854
+ **Lifecycle**: [specify:create][plan:create][tasks:create]
855
+ ```
856
+ - specifyStatus = "create"
857
+ - planStatus = "create"
858
+ - tasksStatus = "create"
859
+ - In Change Summary: marked as **[create]**
860
+
861
+ b. **Modified items** (content changed):
862
+ - Update content in spec
863
+ - **Update Lifecycle** (all three stages):
864
+ ```markdown
865
+ **Lifecycle**: [specify:update][plan:update][tasks:update]
866
+ ```
867
+ - specifyStatus = "update"
868
+ - planStatus = "update" (triggers plan regeneration)
869
+ - tasksStatus = "update"
870
+ - **Note**: Do NOT check/preserve previous planStatus or tasksStatus
871
+ - **Rationale**: Any content change invalidates previous plan/tasks
872
+ - In Change Summary: marked as **[update]**
873
+
874
+ c. **Deprecated items** (no longer needed):
875
+ - Update content in spec
876
+ - **Update Lifecycle** (all three stages):
877
+ ```markdown
878
+ **Lifecycle**: [specify:delete][plan:delete][tasks:delete]
879
+ ```
880
+ - All three fields: specify="delete", plan="delete", tasks="delete"
881
+ - Move to Deprecated Items section at end of spec
882
+ - In Change Summary: marked as **[deprecated]**
883
+ - **Note**: DO NOT preserve old planStatus/tasksStatus values
884
+
885
+ d. **Preserved items** (no changes):
886
+ - **DO NOT update Lifecycle field** - preserve all three values as-is
887
+ - DO NOT include in Change Summary (no status marker)
888
+
889
+ **For User Stories**:
890
+ - **[create]**: Add new User Stories
891
+ - **[update]**: Update existing Story
892
+ - **[deprecated]**: Mark Story as deprecated
893
+ - (unchanged Stories: no Lifecycle update, NOT logged in Change Summary)
894
+
895
+ **For Functional Requirements**:
896
+ - **[create]**: Add new FRs
897
+ - **[update]**: Update existing FRs with new version
898
+ - **[deprecated]**: Mark FRs as deprecated with migration path
899
+ - (unchanged FRs: no Lifecycle update, NOT logged in Change Summary)
900
+
901
+ ⚠️ **Constitution Constraints: no Lifecycle block here** (`T239` / `ISS-212`). A three-line `**For Constitution Constraints**:` block used to sit at this spot, mirroring the US/FR rules — but that section **carries no `**Lifecycle**:` field** and nothing reads one if it did (evidence in the note at the head of these rules). ⇒ **Constraints are added or updated as prose in `## Constitution Constraints`; they are never marked, never logged in the Change Summary, and never propagate downstream.** Re-adding the block would recreate a rule for a class that cannot follow it.
902
+
903
+ **For Deprecated Items section**:
904
+ - Move all deprecated items to this section
905
+ - Include:
906
+ - Original content
907
+ - Deprecation reason
908
+ - Migration path (if applicable)
909
+
910
+ f. **Write updated spec.md**:
911
+ - Include Change Summary at top
912
+ - Include all active (non-deprecated) items
913
+ - Include Deprecated Items section at end
914
+
915
+ g. **Update version metadata**:
916
+ ```markdown
917
+ # Feature Specification: [FEATURE_NAME]
918
+
919
+ **Version**: 0.2
920
+ **Last Updated**: [DATE]
921
+ **Status**: Draft
922
+ ```
923
+
924
+ h. **Return**: SUCCESS (spec updated and ready for planning)
925
+
926
+ 6. **Write the specification to SPEC_FILE** using the template structure, replacing placeholders with concrete details derived from the feature description (arguments) while preserving section order and headings.
927
+
928
+ 7. **Auto-scan for clarifications** ✨ ENHANCED with conditional logic:
929
+
930
+ a. **Determine scan necessity** ✨ NEW:
931
+ ```bash
932
+ if [[ "$UPDATE_MODE" = "false" ]]; then
933
+ # Initial spec: Always run scan
934
+ RUN_SCAN=true
935
+ echo "📋 Running clarification scan on initial spec..."
936
+ else
937
+ # Update spec: Check if there are new/modified FRs
938
+ ADDED_FR_COUNT=$(grep -B1 '\*\*Lifecycle\*\*:.*\[specify:create\]' "$SPEC_FILE" 2>/dev/null | grep -cE "FR-[0-9]+[A-E]?" || true)
939
+ : "${ADDED_FR_COUNT:=0}"
940
+ MODIFIED_FR_COUNT=$(grep -B1 '\*\*Lifecycle\*\*:.*\[specify:update\]' "$SPEC_FILE" 2>/dev/null | grep -cE "FR-[0-9]+[A-E]?" || true)
941
+ : "${MODIFIED_FR_COUNT:=0}"
942
+
943
+ if [[ $ADDED_FR_COUNT -gt 0 ]] || [[ $MODIFIED_FR_COUNT -gt 0 ]]; then
944
+ RUN_SCAN=true
945
+ echo "📋 Running clarification scan ($ADDED_FR_COUNT added, $MODIFIED_FR_COUNT modified)..."
946
+ else
947
+ RUN_SCAN=false
948
+ echo "ℹ️ No new/modified FRs, skipping clarification scan"
949
+ fi
950
+ fi
951
+ ```
952
+
953
+ b. **Invoke clarification scan** (conditional):
954
+ ```bash
955
+ if [[ "$RUN_SCAN" = "true" ]]; then
956
+ /specpro-clarify --scan
957
+ else
958
+ # Load existing clarifications.md
959
+ if [[ -f "specs/clarifications.md" ]]; then
960
+ echo "✓ Loaded existing clarifications.md"
961
+ else
962
+ echo "⚠️ No clarifications.md found (expected for preserved-only update)"
963
+ fi
964
+ fi
965
+ ```
966
+ This scans spec.md for ambiguities and generates/updates `specs/clarifications.md` with categorized questions.
967
+
968
+ c. **Wait for scan completion** (if scan was run): Do not proceed until the scan is complete and clarifications.md is generated.
969
+
970
+ d. **Verify clarifications.md** (if scan was run): Confirm that `specs/clarifications.md` was created successfully. If scan failed, warn user but proceed to commit.
971
+
972
+ 8. **Auto-invoke clarify if needed** 🆕 REDESIGNED:
973
+
974
+ **Purpose**: Automatically check clarifications.md and invoke clarify if [Must Clarify] items exist
975
+
976
+ **Key Changes**:
977
+ - No user choice required - automatic based on clarifications.md content
978
+ - If [Must Clarify] items exist → automatically invoke clarify (interactive)
979
+ - If no [Must Clarify] items → skip to Step 9
980
+ - Seamless user experience - no decision point
981
+
982
+ a. **Read clarifications.md statistics**:
983
+ ```bash
984
+ # ⚠️ **BIND THE PATH FIRST — this line is the whole fix** (`T236` / `ISS-209`): everything
985
+ # below reads `$CLARIFICATIONS_FILE`, and **nothing in this repository ever assigned it**
986
+ # (measured 2026-09-20: 5 uses, 0 assignments). With the variable unset, `[[ ! -f "" ]]` is
987
+ # **true**, so this step printed "✓ No clarifications needed" and returned **before**
988
+ # `$MUST_CLARIFY_COUNT` was ever computed ⇒ the `[Must Clarify]`-driven `/specpro-clarify`
989
+ # hand-off — the entire reason this step exists — was **unreachable by construction**.
990
+ # The literal below is the same one this file already uses at Step 7.c.
991
+ CLARIFICATIONS_FILE="specs/clarifications.md"
992
+
993
+ # Check if clarifications.md exists
994
+ if [[ ! -f "$CLARIFICATIONS_FILE" ]]; then
995
+ echo "✓ No clarifications needed (clarifications.md not found)"
996
+ echo " Proceeding to quality validation..."
997
+ # Skip to Step 9
998
+ return 0
999
+ fi
1000
+
1001
+ # Count items in each category — ⚠️ **ANCHORED ON THE ENTRY FORM, and that is the whole
1002
+ # fix** (`T244` / `ISS-217`): the pattern used to be the bare `"\[<label>\]"`, which
1003
+ # matches **every mention** — the template's own definitions block, its
1004
+ # `### [Must Clarify] Items` heading, the `## Progress Tracking` rows, the
1005
+ # `**Completion Criteria**` line. Measured on a freshly-generated artifact:
1006
+ # **Must Clarify 9 · Suggested Clarify 3 · Can Infer 8** against **1 item each**.
1007
+ # ⚠️ **That is not cosmetic**: `MUST_CLARIFY_COUNT > 0` is the trigger for the
1008
+ # auto-invoked `/specpro-clarify` hand-off below ⇒ an inflated count fires the hand-off
1009
+ # on an artifact with **no** must-clarify items, every time, and nothing reports it.
1010
+ # An entry is `- **[<label>] - <id>** - …` (note the ` - `, which the definition line
1011
+ # `- **[<label>]**: …` does not have, and no mention line starts with `- **`).
1012
+ # ⚠️ Per TOOL-009 this example is itself line-anchored: a copied unanchored pattern is
1013
+ # how the same misjudgment propagates.
1014
+ CLARIFY_ENTRY='^- \*\*\['
1015
+ MUST_CLARIFY_COUNT=$(grep -cE "${CLARIFY_ENTRY}Must Clarify\] - " "$CLARIFICATIONS_FILE" 2>/dev/null || true)
1016
+ : "${MUST_CLARIFY_COUNT:=0}"
1017
+ SUGGESTED_CLARIFY_COUNT=$(grep -cE "${CLARIFY_ENTRY}Suggested Clarify\] - " "$CLARIFICATIONS_FILE" 2>/dev/null || true)
1018
+ : "${SUGGESTED_CLARIFY_COUNT:=0}"
1019
+ CAN_INFER_COUNT=$(grep -cE "${CLARIFY_ENTRY}Can Infer\] - " "$CLARIFICATIONS_FILE" 2>/dev/null || true)
1020
+ : "${CAN_INFER_COUNT:=0}"
1021
+ TOTAL_ITEMS=$((MUST_CLARIFY_COUNT + SUGGESTED_CLARIFY_COUNT + CAN_INFER_COUNT))
1022
+ ```
1023
+
1024
+ b. **Display clarification summary**:
1025
+ ```markdown
1026
+ ## Specification Created ✓
1027
+
1028
+ **Spec File**: [SPEC_FILE path]
1029
+ **Clarifications**: [specs/clarifications.md path]
1030
+
1031
+ **Clarification Summary**:
1032
+ - [Must Clarify]: M items
1033
+ - [Suggested Clarify]: N items
1034
+ - [Can Infer]: K items
1035
+ - **Total**: TOTAL items
1036
+ ```
1037
+
1038
+ c. **Auto-invoke clarify if [Must Clarify] items exist**:
1039
+ ```bash
1040
+ if [[ $MUST_CLARIFY_COUNT -gt 0 ]]; then
1041
+ echo ""
1042
+ echo "🔄 Found $MUST_CLARIFY_COUNT [Must Clarify] items"
1043
+ echo " Automatically starting clarification process..."
1044
+ echo ""
1045
+ echo " AI will ask questions one by one, integrating answers into spec.md"
1046
+ echo " You can also type 'skip' to skip specific questions"
1047
+ echo ""
1048
+
1049
+ # Auto-invoke clarify (interactive mode)
1050
+ /specpro-clarify
1051
+
1052
+ # After clarify completes, check if all [Must Clarify] items are resolved
1053
+ # ⚠️ **This is a BLOCK scan, not a line count** (`T244` / `ISS-217`, same round as the
1054
+ # counts above). Two things were wrong with the one-liner it replaces
1055
+ # (`grep -c "\[Must Clarify\]"`): ① it counted **mentions** (see above), and ② it
1056
+ # counted **entries**, not **unresolved** ones — so with any must-clarify item at all,
1057
+ # `REMAINING_MUST` was **always > 0** and the `✅ All … resolved` branch below was
1058
+ # **unreachable**. The stated intent ("check if all … are resolved") needs each
1059
+ # item's own `**Status**:` line, which is a per-item block read.
1060
+ # ⚠️ The status anchor carries **`[[:space:]]*`** and that is not cosmetic: the
1061
+ # template emits the line **indented** (` **Status**: [ ]`), so a line-start anchor
1062
+ # matches **nothing** and the count comes back a constant 0 — a false "all resolved"
1063
+ # that is indistinguishable from a real one. (Measured while writing this: the first
1064
+ # version of this very fix shipped with the wrong anchor and reported 0 on a fixture
1065
+ # holding an unresolved item.)
1066
+ REMAINING_MUST=$(awk '
1067
+ /^- \*\*\[Must Clarify\] - / { in_item = 1; next }
1068
+ in_item && /^[[:space:]]*\*\*Status\*\*:/ { if ($0 ~ /\[[ ]\]/) unresolved++; in_item = 0 }
1069
+ END { print unresolved + 0 }
1070
+ ' "$CLARIFICATIONS_FILE" 2>/dev/null || true)
1071
+ : "${REMAINING_MUST:=0}"
1072
+
1073
+ if [[ $REMAINING_MUST -gt 0 ]]; then
1074
+ echo ""
1075
+ echo "⚠️ Clarification completed with $REMAINING_MUST unresolved [Must Clarify] items"
1076
+ echo " These will be addressed during quality validation (Step 9)"
1077
+ echo " Proceeding to quality validation..."
1078
+ else
1079
+ echo ""
1080
+ echo "✅ All [Must Clarify] items resolved"
1081
+ echo " Proceeding to quality validation..."
1082
+ fi
1083
+ else
1084
+ echo ""
1085
+ echo "✓ No [Must Clarify] items found"
1086
+ echo " Clarifications.md contains only [Suggested Clarify] and [Can Infer] items"
1087
+ echo " These can be resolved manually or during quality validation"
1088
+ echo " Proceeding to quality validation..."
1089
+ fi
1090
+ ```
1091
+
1092
+ d. **Inform user about next steps**:
1093
+ ```markdown
1094
+ **What to Expect Next**:
1095
+ - Step 9: Quality validation (specpro.qc)
1096
+ * Validates spec.md against the checklist's quality criteria
1097
+ * Rebuilds specs/checklists/requirements.md from the template, every run
1098
+ * Queues every non-passing criterion into the [specify] section of the ledger
1099
+ * Reports a verdict and stops — no repair, no loop (`FR-058` / `FR-060`)
1100
+ * ⚠️ The queued entries are THIS command's to fix, on the next --review-issues run
1101
+
1102
+ - After validation: Git commit with spec.md + clarifications.md + requirements.md
1103
+
1104
+ - Final step: Ready for `/specpro-plan` (technical planning)
1105
+ ```
1106
+
1107
+ **User Experience**:
1108
+ - **No user intervention required**: clarify is invoked automatically when needed
1109
+ - **Seamless flow**: User watches as clarify asks questions and updates spec.md
1110
+ - **No decision point**: No need to choose "clarify now or later"
1111
+ - **Flexibility preserved**: User can still type 'skip' during clarify to skip questions
1112
+
1113
+ **Backward Compatibility**:
1114
+ - If user manually runs `/specpro-clarify` before this step, it will detect no [Must Clarify] items and skip
1115
+ - If user wants to review spec.md first, they can run `/specpro-specify --update` later
1116
+ 9. **Specification Quality Validation** 🆕 REDESIGNED with specpro.qc [MANDATORY - CRITICAL GATE]:
1117
+
1118
+ **Purpose**: Validate the FINAL spec.md (after all clarifications) against the checklist's quality criteria using automated qc command
1119
+
1120
+ ⚠️ **CRITICAL: This step is MANDATORY and NON-SKIPPABLE**
1121
+ - Quality validation CANNOT be bypassed
1122
+ - QC execution is enforced automatically
1123
+ - requirements.md generation is verified post-QC
1124
+ - Workflow BLOCKS if quality validation fails
1125
+
1126
+ **Key Changes** ⚠️ [rewritten 2026-09-19: two of the five lines below described the
1127
+ *repair* behaviour that `FR-058` removed — a command document claiming its callee
1128
+ repairs is how the delegation stayed invisible for as long as it did]:
1129
+ - Quality validation is a dedicated `/specpro-qc` command, not inline logic here
1130
+ - **qc checks and reports; THIS command repairs** — the spec's producer is the only
1131
+ party that writes the spec (`FR-058`)
1132
+ - **qc queues what did not pass into the `[specify]` section** (`FR-059`) — which is
1133
+ this command's own queue, so the fix path stays inside one chain
1134
+ - qc runs **once**, rebuilds the checklist, and stops (`FR-060`); there is no repair
1135
+ loop and therefore no "converged / not feasible" verdict for it to pronounce
1136
+ - No "continue despite issues" option - quality is not compromisable
1137
+ - Post-QC verification ensures requirements.md is generated successfully
1138
+
1139
+ a. **Detect validation scope**:
1140
+ ```bash
1141
+ if [[ "$UPDATE_MODE" = "false" ]]; then
1142
+ # Initial spec: Full validation
1143
+ VALIDATION_SCOPE="full"
1144
+ echo "📋 Running full quality validation (initial spec)..."
1145
+ else
1146
+ # Update spec: Validate only modified/added items
1147
+ ADDED_FR_COUNT=$(grep -B1 '\*\*Lifecycle\*\*:.*\[specify:create\]' "$SPEC_FILE" 2>/dev/null | grep -cE "FR-[0-9]+[A-E]?" || true)
1148
+ : "${ADDED_FR_COUNT:=0}"
1149
+ MODIFIED_FR_COUNT=$(grep -B1 '\*\*Lifecycle\*\*:.*\[specify:update\]' "$SPEC_FILE" 2>/dev/null | grep -cE "FR-[0-9]+[A-E]?" || true)
1150
+ : "${MODIFIED_FR_COUNT:=0}"
1151
+
1152
+ if [[ $ADDED_FR_COUNT -gt 0 ]] || [[ $MODIFIED_FR_COUNT -gt 0 ]]; then
1153
+ VALIDATION_SCOPE="incremental"
1154
+ echo "📋 Running incremental validation ($ADDED_FR_COUNT added, $MODIFIED_FR_COUNT modified)..."
1155
+ else
1156
+ VALIDATION_SCOPE="skip"
1157
+ echo "ℹ️ No new/modified FRs, skipping quality validation"
1158
+ echo "✓ Loading existing quality checklist..."
1159
+ # Skip to Step 10
1160
+ fi
1161
+ fi
1162
+ ```
1163
+
1164
+ b. **Run /specpro-qc** 🆕:
1165
+ ```bash
1166
+ if [[ "$VALIDATION_SCOPE" != "skip" ]]; then
1167
+ echo "📋 Starting quality validation with specpro.qc..."
1168
+ echo " Validating against the checklist's quality criteria..."
1169
+ echo " QC rebuilds the checklist and queues every non-passing item for THIS command."
1170
+
1171
+ # ⚠️ **FR-062's obligation is discharged HERE**: the check runs on the spec's
1172
+ # first creation and on every update, and the trigger is the spec's change —
1173
+ # not the caller's memory. ⚠️ And it is run **flag-less**, because the repair
1174
+ # is not the checker's to perform (FR-058): qc queues the non-passing items
1175
+ # into `[specify]`, and THIS command — the spec's producer — resolves them.
1176
+ /specpro-qc --scope="$VALIDATION_SCOPE"
1177
+
1178
+ QC_EXIT_CODE=$?
1179
+
1180
+ if [[ $QC_EXIT_CODE -eq 0 ]]; then
1181
+ echo ""
1182
+ echo "✅ Quality validation PASSED"
1183
+ echo " No criterion failed."
1184
+ echo " specs/checklists/requirements.md: rebuilt for this run"
1185
+ else
1186
+ echo ""
1187
+ echo "❌ Quality validation FAILED"
1188
+ echo " The non-passing criteria are now entries in the [specify] queue"
1189
+ echo " (FR-059) — this command's own queue, to be fixed by this command."
1190
+ echo ""
1191
+ echo "Check specs/checklists/requirements.md for the per-item verdicts."
1192
+ echo "Then run --review-issues to process the queued entries."
1193
+ exit 1
1194
+ fi
1195
+ else
1196
+ echo "✓ Quality validation skipped (no changes to validate)"
1197
+ fi
1198
+ ```
1199
+
1200
+ c. **Post-QC Verification** 🆕 [MANDATORY - CRITICAL GATE]:
1201
+ ```bash
1202
+ # This step verifies that QC successfully generated requirements.md
1203
+ # If verification fails, the workflow is BLOCKED
1204
+
1205
+ echo ""
1206
+ echo "📋 Post-QC Verification: Checking requirements.md generation..."
1207
+
1208
+ # Derive from the spec file, not from an absolute specs path: in a layout where the
1209
+ # specs directory is its own repository, an absolute path can resolve outside the
1210
+ # tree this run actually wrote to.
1211
+ SPECS_DIR="$(cd "$(dirname "$SPEC_FILE")" && pwd)"
1212
+ REQUIREMENTS_FILE="$SPECS_DIR/checklists/requirements.md"
1213
+
1214
+ if [[ ! -f "$REQUIREMENTS_FILE" ]]; then
1215
+ echo ""
1216
+ echo "❌ CRITICAL: requirements.md not found after QC execution"
1217
+ echo " Expected: $REQUIREMENTS_FILE"
1218
+ echo " Current: File not found"
1219
+ echo ""
1220
+ echo "This indicates a critical workflow failure."
1221
+ echo "Quality validation (QC) should have generated requirements.md but failed to do so."
1222
+ echo ""
1223
+ echo "Workflow is BLOCKED. Please diagnose the issue:"
1224
+ echo "1. Run /specpro-qc manually to check for errors"
1225
+ echo "2. Check if QC is generating requirements.md correctly"
1226
+ echo "3. Verify SPECS_DIR path: $SPECS_DIR"
1227
+ exit 1
1228
+ fi
1229
+
1230
+ # 完成度按「Status 取值」判定,不按复选框——模板即 `- [ ] **Status**: …`,
1231
+ # 「诚实跳过」与「未做」在复选框上完全同形(工具缺陷 #10)
1232
+ QC_UNRESOLVED=$(grep -E '^- \[[ x]\] \*\*Status\*\*:' "$REQUIREMENTS_FILE" 2>/dev/null \
1233
+ | grep -vE '\*\*Status\*\*:[[:space:]]*(x|⊘[[:space:]]*Skipped)[[:space:]]*$' || true)
1234
+
1235
+ if [ -n "$QC_UNRESOLVED" ]; then
1236
+ echo ""
1237
+ echo "❌ CRITICAL: requirements.md has unresolved items after QC execution"
1238
+ echo " Expected: every item is either 'x' (passed) or '⊘ Skipped'"
1239
+ echo ""
1240
+ echo "This indicates QC did not complete successfully."
1241
+ echo ""
1242
+ echo "Unresolved items:"
1243
+ echo "$QC_UNRESOLVED" | head -5
1244
+ echo ""
1245
+ echo "Workflow is BLOCKED. Please diagnose the issue:"
1246
+ echo "1. Run /specpro-qc manually to check for errors"
1247
+ echo "2. Check specs/checklists/requirements.md for details"
1248
+ exit 1
1249
+ fi
1250
+
1251
+ echo "✅ Post-QC Verification PASSED"
1252
+ echo " requirements.md exists with every item marked [x]"
1253
+ echo " Quality validation artifact verified successfully"
1254
+ ```
1255
+
1256
+ **What specpro.qc does** ⚠️ [corrected 2026-09-19 — every line below used to describe
1257
+ the *repair* behaviour that `FR-058` removed]:
1258
+ - Validates spec.md against the checklist's quality criteria:
1259
+ * P0: Content Quality (2 items) - No implementation details, functional not technical
1260
+ * P0: Completeness (3 items) - Mandatory sections, acceptance scenarios, scenarios are functional
1261
+ * P1: Consistency (4 items) - US consistency, FR consistency, US→FR mapping, reference integrity
1262
+ * P1: Traceability (2 items) - Constitution constraints, external dependencies
1263
+ - **Rebuilds** `specs/checklists/requirements.md` from the template, **every run** (`FR-060`)
1264
+ - **Queues every non-passing criterion** into the `[specify]` section of
1265
+ `specs/implement_issues.md` (`FR-059`) — deduped by check id, so repeated runs do
1266
+ not flood the queue
1267
+ - **Reports a verdict and stops** (`FR-061`): passing means "no `✗`"; a `⊘ Skipped`
1268
+ item is neither a pass nor a failure
1269
+ - ⚠️ **It does NOT fix anything, does NOT write `spec.md`, does NOT touch
1270
+ `clarifications.md`, and does NOT loop** — see the write-surface note at the top of
1271
+ `commands/specpro.qc.md`. The repair is **this** command's job.
1272
+
1273
+ **No user intervention required**:
1274
+ - User does not need to call /specpro-qc manually
1275
+ - User does not need to fix issues manually
1276
+ - All interactions happen through clarify (AI asks questions)
1277
+ - If qc cannot resolve issues, project is marked as not feasible
1278
+
1279
+ 10. **Create Git commit** (after writing spec.md, clarifications.md, and checklists/requirements.md):
1280
+
1281
+ a. **Resolve the repository that owns the spec artifacts** ⚠️:
1282
+ The artifacts this step commits may not live in the same repository as the project root. A project may keep its plan/task artifacts in a **separate repository** — e.g. a nested repo mounted at the specs directory — and a commit issued from the project root would then see them as untracked-ignored or not at all.
1283
+
1284
+ Derive the specs directory from the spec file itself, then resolve the owning repository from that path — do not assume the project root, and do not rely on a `SPECS_DIR` variable this command never sets:
1285
+ ```bash
1286
+ SPECS_DIR="$(cd "$(dirname "$SPEC_FILE")" && pwd)"
1287
+ SPECS_REPO="$(git -C "$SPECS_DIR" rev-parse --show-toplevel 2>/dev/null)" || SPECS_REPO=""
1288
+ if [ -z "$SPECS_REPO" ]; then
1289
+ echo "ℹ️ The specs directory is not under version control — skipping commit"
1290
+ SPEC_COMMIT_SKIP=true
1291
+ else
1292
+ SPEC_COMMIT_SKIP=false
1293
+ fi
1294
+
1295
+ # Relative-path helper. Use the Python form directly — macOS `realpath(1)` has no
1296
+ # `--relative-to`.
1297
+ #
1298
+ # ⚠️ **`os.path.realpath` on BOTH sides is the whole point, not a nicety** (ISS-144):
1299
+ # `os.path.relpath` only compares literal prefixes. `git rev-parse --show-toplevel` returns
1300
+ # the PHYSICAL path (symlinks resolved) while `$SPECS_DIR` below comes from `cd … && pwd`
1301
+ # (logical) — so when a project is reached through a symlink the two do not share a prefix
1302
+ # and relpath walks ABOVE the repository. Reproduced: with `/tmp` → `/private/tmp`,
1303
+ # `relpath` produced `../../../../tmp/.../specs/spec.md` for a file inside the repo, and
1304
+ # `git add` then refused it as outside the repository. Resolving both sides collapses the
1305
+ # difference. ⚠️ Copied verbatim in `specpro.implement.md` and `specpro.test-implement.md`
1306
+ # — change all three together.
1307
+ relpath() { python3 -c 'import os,sys;print(os.path.relpath(os.path.realpath(sys.argv[2]),os.path.realpath(sys.argv[1])))' "$1" "$2"; }
1308
+ ```
1309
+ 🔴 **`SPECS_REPO=""` means STOP — and the empty string is a trap, not a sentinel.** `git -C ""` does **not** mean "no repository"; it means **the current directory**, so it silently resolves to whatever repository the cwd happens to be in. Verified 2026-09-18: `git -C "" rev-parse --show-toplevel` → the cwd's repository, **exit 0**. ⇒ With `SPECS_REPO=""`, every step below would run against the **wrong** repository while the line above says "skipping" — the failure is not an error but a **silent commit into the wrong repo**. **If `SPEC_COMMIT_SKIP=true`, do NOT run steps 10b–10e at all.** Report it and end this step: the artifacts stay uncommitted, which is the honest outcome (**FR-030** — 明确报告并跳过,而非以一个不解析的路径失败).
1310
+
1311
+ All git commands below run against `$SPECS_REPO`, not `$REPO_ROOT`. Each artifact path is expressed **relative to that repository** — never as a literal `specs/...` path, which is only correct when the project root *is* the owning repository:
1312
+ ```bash
1313
+ SPEC_FILE_REL="$(relpath "$SPECS_REPO" "$SPEC_FILE")"
1314
+ ```
1315
+
1316
+ b. **Check if in Git repository** — ⛔ **GUARD FIRST: if `$SPEC_COMMIT_SKIP` is `true`, skip steps 10b–10e entirely** (see 10a's trap note — an empty `$SPECS_REPO` makes every `git -C` below act on the cwd's repository):
1317
+ ```bash
1318
+ [ "${SPEC_COMMIT_SKIP:-false}" = true ] && echo "⛔ SPEC_COMMIT_SKIP — steps 10b–10e are skipped (FR-030)"
1319
+ # ...and do not run the lines below when that printed.
1320
+ if git -C "$SPECS_REPO" rev-parse --git-dir > /dev/null 2>&1; then
1321
+ IN_GIT_REPO=true
1322
+ else
1323
+ IN_GIT_REPO=false
1324
+ fi
1325
+ ```
1326
+
1327
+ c. **Check if spec.md has changes**:
1328
+ ```bash
1329
+ if git -C "$SPECS_REPO" diff --quiet -- "$SPEC_FILE_REL" 2>/dev/null; then
1330
+ echo "ℹ️ No changes to spec.md, skipping commit"
1331
+ else
1332
+ SPEC_CHANGED=true
1333
+ fi
1334
+ ```
1335
+
1336
+ d. **Generate commit message**:
1337
+ ```bash
1338
+ if [ "$UPDATE_MODE" = true ]; then
1339
+ # For updates, include version and summary
1340
+ CHANGE_SUMMARY=$(grep "^### Changes Overview" "$SPEC_FILE" -A 10 | head -15)
1341
+ COMMIT_MSG="spec: update to v${SPEC_VERSION}
1342
+
1343
+ ${CHANGE_SUMMARY}"
1344
+ else
1345
+ # For initial spec
1346
+ COMMIT_MSG="spec: initial specification v${SPEC_VERSION}"
1347
+ fi
1348
+ ```
1349
+
1350
+ e. **Create commit** (in the owning repository, with paths relative to it) — ⛔ **the write step, wrapped so an unowned path cannot reach it**:
1351
+ ```bash
1352
+ if [ "${SPEC_COMMIT_SKIP:-false}" = true ]; then
1353
+ echo "⛔ refused: no owning repository — nothing is committed (FR-030)"
1354
+ else
1355
+ git -C "$SPECS_REPO" add -- \
1356
+ "$SPEC_FILE_REL" \
1357
+ "$(relpath "$SPECS_REPO" "$SPECS_DIR/clarifications.md")" \
1358
+ "$(relpath "$SPECS_REPO" "$SPECS_DIR/checklists/requirements.md")"
1359
+ git -C "$SPECS_REPO" commit -m "$COMMIT_MSG"
1360
+ fi
1361
+ ```
1362
+ ⚠️ **The `if` is the point, not decoration**: it makes "commit into the wrong repository" **unreachable by construction** rather than dependent on the reader having followed the prose in 10a. Branching on a flag set where the repository was resolved is what FR-030 asks for — 明确报告并跳过,而不是继续走到一个解析不出来的路径上。
1363
+ ⚠️ If the artifacts span **more than one repository** (e.g. the spec lives in one repo and a checklist in another), issue **one commit per repository**, each with a message describing that repository's change. A single commit cannot span repositories.
1364
+
1365
+ f. **Optional: Create tag**:
1366
+ ```bash
1367
+ echo "Consider creating a tag for this version:"
1368
+ echo " git tag -a v${SPEC_VERSION}-spec -m \"Specification v${SPEC_VERSION}\""
1369
+ ```
1370
+
1371
+ g. **Commit successful message**:
1372
+ ```markdown
1373
+ ✓ Specification committed successfully
1374
+
1375
+ **Commit Hash**: [commit hash]
1376
+ **Message**: $COMMIT_MSG
1377
+
1378
+ **Documents Committed**:
1379
+ - specs/spec.md (specification)
1380
+ - specs/clarifications.md (clarification questions)
1381
+ - specs/checklists/requirements.md (quality validation)
1382
+
1383
+ **Clarification Summary**:
1384
+ - [Must Clarify]: M items
1385
+ - [Suggested Clarify]: N items
1386
+ - [Can Infer]: K items
1387
+
1388
+ **Quality Validation Summary** (fields verbatim from `specs/checklists/requirements.md`):
1389
+ - Status: [PASS | BLOCK]
1390
+ - Total Items: X
1391
+ - Passed: Y
1392
+ - Skipped: S
1393
+ - Failed: Z
1394
+
1395
+ **Important**:
1396
+ - If you ran clarification, your spec.md has been significantly updated
1397
+ - Please review specs/spec.md to verify the changes
1398
+ - Please review specs/checklists/requirements.md for quality issues
1399
+
1400
+ **Upstream status reconciliation** ⚠️ [MANDATORY before any "ready to continue" — Constraint 6 / FR-045]
1401
+
1402
+ **"Ready to continue" is a claim about the whole chain, not about the stage speaking.** So
1403
+ before this report states any "can continue / ready" conclusion, it MUST **read** each upstream
1404
+ stage's pending status on the entries that stage produced, and **state** what it found. The
1405
+ over-declaration this replaces: `/specpro-tasks` closed with "✅ Ready to continue
1406
+ implementation" while the design side had not taken a single step (`specs/plan.md` → Constraint 6).
1407
+
1408
+ **Two things, neither optional**:
1409
+
1410
+ 1. **Say it when the status is clean too.** "Nothing was mentioned" and "nothing is pending"
1411
+ are different statements, and the first cannot be told apart from "forgot to look".
1412
+ 2. **Skipped and processed counts are listed separately** — never merged into one "handled" number.
1413
+
1414
+ **Report shape** — every upstream gets a line, **including when it has nothing pending**
1415
+ (indented, not fenced: several of these blocks sit inside an enclosing fence, and a nested
1416
+ fence would close the outer one early):
1417
+
1418
+ Upstream reconciliation (Constraint 6)
1419
+ <upstream>: N pending · M processed
1420
+ Verdict: <clear to continue | upstream debts listed above>
1421
+
1422
+ ⚠️ **Report — do not block.** The mechanism self-heals: an upstream that completes marks its
1423
+ downstream `update`. Blocking would need a judgement of "what counts as a debt", and that
1424
+ judgement *is* the downstream reading its upstreams — reporting is its only legitimate form.
1425
+
1426
+ ⚠️ **Copied verbatim across `specpro.{specify,plan,tasks,test-plan,test-implement}.md`** (five
1427
+ sites; do not exist as one because each command document is deployed and read on its own).
1428
+ Only the "This stage's upstreams" line below differs per file — **change all five together**.
1429
+
1430
+ **This stage's upstreams**: `constitution` — pending means a constraint it states is not
1431
+ carried into this spec (`specs/constitution.md` → the constraint list).
1432
+
1433
+ **Next Steps**:
1434
+ 1. Review specs/spec.md to verify the updates
1435
+ 2. Review specs/checklists/requirements.md for quality issues
1436
+ 3. Run /specpro-plan to create technical plan
1437
+ - Note: /specpro-plan will auto-invoke clarification if [Must Clarify] items remain
1438
+ ```
1439
+
1440
+ ---
1441
+
1442
+ ## Protocol Codec Module Rules 🌐 [CONDITIONAL — FRs touching a wire format]
1443
+
1444
+ **Activation**: decided by the **Activation Gate** (`.specpro/templates/protocol-golden-bytes-guide.md` §6) — triggers T1/T2 (a byte-level protocol anchor or a named protocol in the requirement text) put an FR in scope for that field. "Partially protocol" is not a category: a requirement touching one wire field is in scope for that field. The verdict is recorded per §6.4, not left implicit — producing neither the artifacts nor an explicit not-active verdict is the failure the gate exists to catch. When activated, the FR text MUST meet the requirements below.
1445
+
1446
+ - A protocol FR MUST state three specifications explicitly: **stream semantics** (continuous single stream vs per-message independent stream); **byte-packing rules** (which layer owns bit-depth decisions, where dynamic branch selection happens, and known peer-implementation differences); and **peer diversity** (the measured list of differences between peer implementations).
1447
+ - The wording MUST NOT infer stream-internal byte counts by translating a parameter such as bits-per-pixel — stream-internal format follows what the encoder or peer actually emits, and every such claim MUST carry its source layer (L1 specification / L2 reference implementation / L3 captured stream; definitions in `.specpro/templates/protocol-golden-bytes-guide.md` §2).
1448
+ - The protocol-point inventory itself is a plan-layer design decision; the spec's job is to state the requirement that such an inventory exists.
1449
+