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,1102 @@
1
+ ---
2
+ description: Perform comprehensive cross-artifact consistency and quality analysis with trend tracking capabilities
3
+ writes:
4
+ # This command's write surface: only what it produces AS THE PRODUCER of that
5
+ # (artifact, unit) pair. A write this command makes on a non-producer path is a
6
+ # boundary violation by definition (FR-051) and MUST NOT be declared here.
7
+ # The full ownership map is the UNION of every command's writes: block.
8
+ - artifact: specs/implement_issues.md
9
+ unit: "each stage section ([specify]/[plan]/[tasks]/[test-plan]/[constitution]) -> appended ISS-NNN entries; the top statistics table"
10
+ - artifact: specs/analysis/analysis-[timestamp].md
11
+ unit: "whole file - one timestamped report per run (--persist only)"
12
+ ---
13
+
14
+ ## User Input
15
+
16
+ ```text
17
+ $ARGUMENTS
18
+ ```
19
+
20
+ You **MUST** consider the user input before proceeding (if not empty).
21
+
22
+ **Rerun safety — read-only over the artifacts** ⚠️ [settled 2026-09-13]:
23
+
24
+ This command **never regenerates a design artifact**. It reads `spec.md` / `plan.md` / `tasks.md` / `test-tasks.md` / `contracts/**` and reports; the shared rerun rule (*detect the artifact; absent → initial, present → incremental*) applies to the commands that **write** those artifacts, not here.
25
+
26
+ **Its only writes** (see Operating Constraints):
27
+ | Write | Rule |
28
+ |-------|------|
29
+ | Append entries to `specs/implement_issues.md` | **Append only** — never rewrite the file. ⚠️ **Appending into another command's section is NOT a violation — it is this ledger's routing act** (`ISS-92` / `T174`): the Routing table below exists precisely to decide *which* section a finding belongs to. What is forbidden is **marking** another section's entries `[x]` — 登记即路由(不限分区)· 标记限于本分区 |
30
+ | `specs/analysis/` results (only with `--persist`) | New timestamped artefact per run; adds, never replaces |
31
+
32
+ Anything else — including "fixing" a finding it reported — belongs to the owning `--review-issues` run.
33
+
34
+ > **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, and three had none — not by decision, but because the discipline had no shared carrier. The rule everywhere else is: **detect the artifact; absent → initial, present → incremental; overwriting requires explicit AND re-confirmed intent.** This command's read-only posture means it never triggers the third clause.
35
+
36
+
37
+ ### Scope Resolution 🆕 (FR-063 / T050 · v0.23)
38
+
39
+ 1. **作用域判定**: 当前工作目录位于 `specs/fNNN-简称/` 内 ⇒ **feature 作用域**(读写范围 = 本 feature 目录,由 `check-prerequisites.sh` 的作用域感知解析);位于仓库根或 `specs/` 根 ⇒ **母作用域**(读写母规格链)。feature 作用域内 MUST NOT 写母产物——唯一例外:**发现登记**(台账路由,`[specify]`/`[plan]` 分区)。
40
+ 2. **新会话首次执行**: 若 `specs/features.md` 存在且含 `active` 行、而用户未指明作用域 ⇒ **询问用户**在母作用域还是某个 feature 内工作,MUST NOT 自行挑选。
41
+ 3. 本命令的产物路径随之解析:feature 作用域下落 `<feature 目录>/`,母作用域下落 `specs/`。
42
+
43
+ ## Goal
44
+
45
+ Identify inconsistencies, duplications, ambiguities, and underspecified items across the three core artifacts (`spec.md`, `plan.md`, `tasks.md`) before implementation. This command MUST run only after `/specpro-tasks` has successfully produced a complete `tasks.md`.
46
+
47
+ ## Command Options ✨ ENHANCED
48
+
49
+ **Mode Selection**:
50
+ - `--incremental` 🆕: Only analyze items whose `[specify:…]` 段是 `create`/`update`(其余按 Lifecycle 的取值跳过)。⚠️ 本节此前写的是 `SpecStatus=Draft/Modified (skip Stable)`(`T174`)—— **`Draft`/`Stable` 不在 Lifecycle 的取值表里**(那是 `create|update|delete|processed|deprecated`)⇒ 照它过滤**在本仓库的任何产物上都匹配不到**,于是「增量」与「全量」同形,而**没有任何东西会报错**。
51
+ - `--summary` 🆕: Show condensed summary report only
52
+ - `--detail` 🆕: Show detailed analysis report (default)
53
+ - `--persist` 🆕: Save analysis results to specs/analysis/ for trend tracking
54
+
55
+ **Examples**:
56
+ ```bash
57
+ /specpro-analyze # Read-only, full analysis
58
+ /specpro-analyze --incremental # Only analyze changed items
59
+ /specpro-analyze --summary # Quick summary
60
+ /specpro-analyze --persist # Save for trend tracking
61
+ ```
62
+
63
+ ## Operating Constraints
64
+
65
+ **Default Mode (READ-ONLY, with one narrow write)**: Do **not** modify the analyzed artifacts — `spec.md`, `plan.md`, `tasks.md`, `specs/contracts/**`, or any source file. Output a structured analysis report; offer an optional remediation plan (the user must explicitly approve before any follow-up editing commands are invoked).
66
+
67
+ The **single exception** is Step 7 (Finding Registration), which appends entries to `specs/implement_issues.md`. That file is the loop's queue, not an analyzed artifact: a finding that is not recorded there cannot be consumed by the stage that owns the fix, and the manual transcription it would otherwise require is where findings lose their specifics. Recording what was found is analysis; changing what was found to be wrong belongs to the owning `--review-issues` run.
68
+
69
+ **There is no auto-fix mode** ⚠️ [settled 2026-09-18, `ISS-141` / `T184`]: this command **reports**; it does not repair. Its write surface is the ledger and `specs/analysis/` — `spec.md` / `plan.md` / `tasks.md` are **not** among them, so "apply the fix here" was a boundary violation **by definition** (FR-051), not a matter of permission. Declaring it unavailable is therefore not a narrowing of what this command may do; it is the correction of a claim that was never true.
70
+ >
71
+ > ⚠️ **And the rule is not merely formal.** A finding is fixed by the command that **owns** the artifact, in that command's `--review-issues` run. A judge that repairs what it judged has spent its verdict — the repair would then be exempt from the very check that produced it (**Constitution, Principle III**; the same root cause as the test loop's rule that the test used for re-verification may not itself be edited).
72
+
73
+ **Constitution Authority**: The project constitution (`specs/constitution.md`) is **non-negotiable** within this analysis scope. Constitution conflicts are automatically CRITICAL and require adjustment of the spec, plan, or tasks—not dilution, reinterpretation, or silent ignoring of the principle. If a principle itself needs to change, that must occur in a separate, explicit constitution update outside `/specpro-analyze`.
74
+
75
+ ## Execution Steps
76
+
77
+ ### 1. Initialize Analysis Context
78
+
79
+ Run `.specpro/scripts/bash/check-prerequisites.sh --json --require-tasks --include-tasks` once from repo root and parse JSON for FEATURE_DIR and AVAILABLE_DOCS. Derive absolute paths:
80
+
81
+ - SPEC = FEATURE_DIR/spec.md
82
+ - PLAN = FEATURE_DIR/plan.md
83
+ - TASKS = FEATURE_DIR/tasks.md
84
+
85
+ Abort with an error message if any required file is missing (instruct the user to run missing prerequisite command).
86
+ For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
87
+
88
+ **Detection of operation mode** ✨ NEW:
89
+
90
+ **Step 1a: Parse user-provided flags**:
91
+ - Check for `--incremental` flag: Set INCREMENTAL_MODE=true
92
+ - Check for `--summary` flag: Set SUMMARY_MODE=true
93
+ - Check for `--persist` flag: Set PERSIST_MODE=true
94
+
95
+ **Step 1b: Interactive mode selection (if no flags provided)** ✨ ENHANCED:
96
+
97
+ If `$ARGUMENTS` is empty (no user flags), detect context and prompt for mode selection:
98
+
99
+ ```markdown
100
+ ## 📊 Analysis Mode Selection
101
+
102
+ No analysis mode specified. Please choose the appropriate mode:
103
+
104
+ **Context Detection**:
105
+ - Previous analyses exist: [YES/NO]
106
+ - Recent changes detected: [N modified items]
107
+ - Analysis history: [N analyses available]
108
+
109
+ ---
110
+
111
+ ### Mode Options:
112
+
113
+ **1. Standard Analysis** (Recommended for first-time or comprehensive check)
114
+ - Full analysis of all artifacts
115
+ - All 16 detection passes (A–P)
116
+ - Detailed report with findings
117
+ - No automatic fixes
118
+ - Time: ~25 seconds
119
+ - Use when: You want a complete quality check
120
+
121
+ **2. Quick Summary** 🆕 (Recommended for fast status check)
122
+ - Condensed summary report only
123
+ - Overall quality score
124
+ - Issue counts by severity
125
+ - Top 3 next actions
126
+ - Time: ~10 seconds
127
+ - Use when: You need a quick status overview
128
+
129
+ **3. Incremental Analysis** (Recommended if you have recent changes)
130
+ - Only analyze modified items (N items changed)
131
+ - 60-80% faster than full analysis
132
+ - All detection passes applied to changes only
133
+ - Time: ~5-10 seconds
134
+ - Use when: You've made small updates since last analysis
135
+
136
+ **4. Analysis with Trend Tracking** (Recommended for quality monitoring)
137
+ - Full analysis + save results for trend tracking
138
+ - Stores in `specs/analysis/`
139
+ - Generates quality trend over time
140
+ - Integrates with `/specpro-status` dashboard
141
+ - Time: ~25 seconds
142
+ - Use when: You want to track quality improvements over time
143
+
144
+ **5. Custom Mode** (Advanced users)
145
+ - Specify custom combination of flags
146
+ - Examples: --incremental --summary, --persist --summary
147
+ - Use when: You know exactly what you need
148
+
149
+ ---
150
+
151
+ Your choice (1-6):
152
+ ```
153
+
154
+ **Step 1c: Execute selected mode**:
155
+
156
+ After user selection:
157
+
158
+ - **Choice 1**: Set no flags (standard full analysis)
159
+ - **Choice 2**: Set SUMMARY_MODE=true
160
+ - **Choice 3**: Set INCREMENTAL_MODE=true
161
+ - **Choice 4**: Set PERSIST_MODE=true
162
+ - **Choice 5**: Ask user for custom flags, or show flag reference:
163
+ ```markdown
164
+ **Available Flags**:
165
+ --incremental Only analyze modified items (60-80% faster)
166
+ --summary Show condensed summary only
167
+ --persist Save results for trend tracking
168
+
169
+ **Examples**:
170
+ /specpro-analyze --persist --summary
171
+ /specpro-analyze --incremental --summary
172
+
173
+ Enter your custom flags (or leave empty for standard analysis):
174
+ ```
175
+
176
+ **Step 1d: Smart recommendation** 🆕:
177
+
178
+ Before showing the mode selection, provide intelligent recommendation based on context:
179
+
180
+ ```markdown
181
+ **AI Recommendation**: [Mode Name]
182
+
183
+ **Reason**: [Why this mode is recommended based on current context]
184
+
185
+ Examples:
186
+ - "This is your first analysis → Standard Analysis (1)"
187
+ - "You have 3 modified items → Incremental Analysis (3)"
188
+ - "You have 2 prior analyses → Trend Tracking (4)"
189
+ ```
190
+
191
+ **Context Detection Rules**:
192
+ - **First-time analysis** (no `specs/analysis/` directory): Recommend Standard Analysis
193
+ - **Recent changes**(`[specify:update]` 的条目 > 0): Recommend Incremental Analysis
194
+ - **Previous issues found** (last analysis has HIGH/CRITICAL): Recommend Standard Analysis — the previous findings are the subject to **re-measure**, not to repair here. ⚠️ The repair belongs to the artifact's **owning** command, in its `--review-issues` run (`ISS-141`)
195
+ - **Multiple analyses exist** (>2 analyses in `specs/analysis/`): Recommend Trend Tracking
196
+ - **Large specification** (>200 requirements): Recommend Summary or Incremental
197
+
198
+ ### 2. Load Artifacts (Progressive Disclosure) ✨ ENHANCED with Lifecycle filtering
199
+
200
+ Load only the minimal necessary context from each artifact:
201
+
202
+ **From spec.md:**
203
+
204
+ - Overview/Context
205
+ - Functional Requirements (filter by SpecStatus if INCREMENTAL_MODE=true)
206
+ - Non-Functional Requirements (filter by SpecStatus if INCREMENTAL_MODE=true)
207
+ - User Stories (filter by SpecStatus if INCREMENTAL_MODE=true)
208
+ - Edge Cases (if present)
209
+
210
+ **Lifecycle-Aware Filtering** 🆕 (if INCREMENTAL_MODE=true):
211
+ - Only load items whose `[specify:…]` 是 `create` 或 `update`
212
+ - Skip everything else — ⚠️ **the skip set is the complement of the line above; do not write a second predicate for it.** This line used to read `Skip items with SpecStatus=Stable`: `Stable` is **not a value in the Lifecycle vocabulary**, so the predicate selected **nothing**, skipped nothing, and read as a working filter(`T174` 词汇族)—— and it also contradicted the line above it, which already defines the loaded set. ⚠️ **`[specify:processed]` is not the fix either**: that value has **no writer anywhere in the tree**(`ISS-220`)⇒ a predicate over it matches nothing. The set is defined by `[specify:…]` ∈ {`create`,`update`} alone.
213
+ - Filter by `[tasks:…]`(取值同 Lifecycle 表;跳过 `processed`/`deprecated`)
214
+ - This enables fast incremental analysis of only changed items
215
+
216
+ **From plan.md:**
217
+
218
+ - Architecture/stack choices
219
+ - Data Model references
220
+ - Technical constraints
221
+
222
+ > ⚠️ **No `Phases` entry here** (settled 2026-09-13): this list states what the audit actually extracts, and the Phases/Implementation Plan section is **human-read plan information** with no machine consumer — declaring it here told the reader the audit used something it never read. Do not re-add an entry unless a pass genuinely consumes it.
223
+
224
+ **From tasks.md:**
225
+
226
+ - Task IDs
227
+ - Descriptions
228
+ - Phase grouping
229
+ - Parallel markers [P]
230
+ - Referenced file paths
231
+
232
+ **From constitution:**
233
+
234
+ - Load `specs/constitution.md` for principle validation
235
+
236
+ **From checklists/** (if exists) 🆕:
237
+ - Load checklists/requirements.md for quality status
238
+ - Load checklists/*.md for additional quality gates
239
+
240
+ **From test-tasks.md (if exists)** 🆕:
241
+ - Coverage matrix (FR × layer × task ID × status × rationale); note the status enum: `pending-impl`/`manual`/`not-applicable`/`deprecated` are planning verdicts, `not-started`/`in-progress`/`completed` are execution states
242
+ - Test task IDs (INF/IT/CE/AE prefixes) and completion state (`[ ]`/`[x]`); `[DELETED]`-marked tasks are stale entries awaiting physical removal by test-plan
243
+ - **Matrix Change Log + Test-plan Runs log**: the processing record — the most recent entries tell which FRs were last re-processed; used by Pass J staleness detection
244
+ - If missing: record "test coverage matrix not built" for Pass J (recommend running `/specpro-test-plan`)
245
+
246
+ ### 3. Build Semantic Models
247
+
248
+ Create internal representations (do not include raw artifacts in output):
249
+
250
+ - **Requirements inventory**: Each functional + non-functional requirement with a stable key (derive slug based on imperative phrase; e.g., "User can upload file" → `user-can-upload-file`)
251
+ - **User story/action inventory**: Discrete user actions with acceptance criteria
252
+ - **Task coverage mapping**: Map each task to one or more requirements or stories (inference by keyword / explicit reference patterns like IDs or key phrases)
253
+ - **Constitution rule set**: Extract principle names and MUST/SHOULD normative statements
254
+ - **Test task mapping** 🆕: Map test tasks to implementation tasks for Test-First validation
255
+ - **Test coverage matrix** 🆕: From specs/test-tasks.md (if present), map each FR to its coverage cells (unit / integration / component E2E / app E2E) with task IDs, status, and rationale; FRs absent from the matrix count as untracked
256
+
257
+ ### 4. Detection Passes (Token-Efficient Analysis) ✨ ENHANCED
258
+
259
+ Focus on high-signal findings. Limit to 50 findings total; aggregate remainder in overflow summary.
260
+
261
+ **⚠️ The pass count MUST equal the enumeration — and here is the check** (`T147` / `ISS-52`):
262
+
263
+ 任何声称"N 个检测通道"的地方,其 N MUST 等于本文档 `^#### [A-Z]\. ` 的枚举条数。**可复跑**:
264
+
265
+ ```bash
266
+ [ "$(grep -cE '^#### [A-Z]\. ' commands/specpro.analyze.md)" = "16" ] || echo "通道数与枚举不符"
267
+ grep -nE 'All [0-9]+ detection|检测通道' commands/specpro.analyze.md # 逐处核它印的数
268
+ ```
269
+
270
+ ⚠️ **为什么这条要写在这里**:该数此前**声称 15 而实为 14**(直到新增 Pass O 才凑巧对上)——**新增或删除一条通道时,唯一该被更新的那个数字没有任何东西比对**。⚠️ **示例自身用行首锚**(`TOOL-009`):一个无锚的示例会被照抄,然后数进正文里提到通道的行。
271
+
272
+ #### A. Duplication Detection
273
+
274
+ - (MEDIUM) Identify near-duplicate requirements — consolidation improves quality but breaks nothing; never a gate-level finding
275
+ - (MEDIUM) Mark lower-quality phrasing for consolidation — same rationale
276
+
277
+ #### B. Ambiguity Detection
278
+
279
+ - (MEDIUM) Flag vague adjectives (fast, scalable, secure, intuitive, robust) lacking measurable criteria — meaning exists but is unmeasured; `/specpro-clarify` can resolve it
280
+ - (HIGH) Flag unresolved placeholders (TODO, TKTK, ???, `<placeholder>`, etc.) — a placeholder is a requirement that cannot be executed or accepted; it fails the completeness gate, not just its polish
281
+
282
+ #### C. Underspecification
283
+
284
+ - (HIGH) Requirements with verbs but missing object or measurable outcome — nothing to accept against; the acceptance step has no input
285
+ - (MEDIUM) User stories missing acceptance criteria alignment — scenarios exist downstream but drift risk is real, not certain
286
+ - (HIGH) Tasks referencing files or components not defined in spec/plan — the task has no home; the same shape that stranded the install work when `plan.md` named no test tree
287
+
288
+ #### D. Constitution Alignment
289
+
290
+ - (CRITICAL) Any requirement or plan element conflicting with a MUST principle — per this command's own Constitution Authority clause: constitution conflicts are automatically CRITICAL
291
+ - (HIGH) Missing mandated sections or quality gates from constitution — the mandated artifact is absent, so every downstream stage runs without a control it is required to have
292
+
293
+ #### E. Coverage Gaps
294
+
295
+ **⚠️ Two independent coverage dimensions — do NOT report one under the other's name** ⚠️:
296
+
297
+ "Coverage" names two different things in this project, and they are measured against different artifacts with different owners. A number for one is NOT evidence about the other, and a run that reports only one of them will read as "coverage is fine" while the other is wide open:
298
+
299
+ | Dimension | Question | Artifact measured | Planned by |
300
+ |-----------|----------|-------------------|------------|
301
+ | **Task coverage** | Does every FR/SR have an implementing task? | `tasks.md` — `T-nnn` references to FR IDs | `/specpro-tasks` |
302
+ | **Test-matrix coverage** | Does every FR have a row in the coverage matrix? | `specs/test-tasks.md` — matrix rows | `/specpro-test-plan` |
303
+
304
+ Report **both**, by name, as separate numbers.
305
+
306
+ **Task coverage** (the original rule):
307
+ - (HIGH) Requirements with zero associated tasks — report the **count and the FR list**, not only a total. Rationale (measured): a coverage figure of 100% once stood next to ~80 FRs with no task; untasked FRs make "complete" unfalsifiable
308
+ - (MEDIUM) Tasks with no mapped requirement/story — work without a requirement behind it cannot be verified against anything
309
+ - (MEDIUM) Non-functional requirements not reflected in tasks (e.g., performance, security)
310
+
311
+ **Test-matrix coverage**: covered by Pass J (matrix staleness / FRs missing from the matrix). Do not fold its numbers into this pass's, and do not let a clean matrix (e.g. "168/168 rows") stand in for task coverage — the two can differ by half the FR set. **Worked instance (2026-09-10)**: the matrix read 168/168 = 100% while task coverage was 88/168 = 52%; the run reported "zero-coverage FRs: 0" from the matrix figure and registered nothing, leaving ~80 FRs with no task and no finding. A finding here is only as good as the artifact it was measured on — name the artifact in the finding's evidence.
312
+
313
+ **Legacy caveat — a Lifecycle field may be stale DATA in this project** ⚠️: a field that is constant across every item means the field was **never maintained by its owning command in this project** — it is a **data-state observation, NOT a verdict on the field's semantics or on the mechanism**.
314
+ Worked instance: this project's `[plan:*]`/`[tasks:*]` are `processed` on all items because the spec was written wholesale (`05590ee`, 2026-01-26) **before** the task system existed — for a project that runs the workflow in order, the same fields carry real discrimination and driving the per-layer increment off them is **correct usage**. Decisive counter-evidence in the same file: `[specify:*]` **does** discriminate (171 `processed` + 8 `update`, matching the last two spec revisions) — same mechanism, same file, and the leg the mechanism actually maintained is correct.
315
+ So: report the constancy as **stale data** (a project-level annotation), and never generalise it into a rule that the field is useless or that filtering on it is forbidden. **Do not derive task coverage from it** — coverage is a measurement (Pass E's carrier test), a different question from "which items are queued for processing".
316
+
317
+ #### F. Inconsistency
318
+
319
+ - Terminology drift (same concept named differently across files)
320
+ - Data entities referenced in plan but absent in spec (or vice versa)
321
+ - Task ordering contradictions (e.g., integration tasks before foundational setup tasks without dependency note)
322
+ - Conflicting requirements (e.g., one requires Next.js while other specifies Vue)
323
+
324
+ **Lifecycle marker vs measured reality** 🆕 — a marker asserting a state the artifacts do not show:
325
+ - An FR/SR marked `[tasks:processed]` (or `[plan:processed]`) with **no carrier** — see the carrier test below
326
+ - Any Lifecycle field that is **constant across every item** — report it as **stale data in this project** (the owning command has never run against these items), **not** as a defect of the field or of the mechanism. State which leg is affected and, as counter-evidence, whether the *other* legs still discriminate (measured 2026-09-13: `[plan:*]`/`[tasks:*]` constant on 172/172 while `[specify:*]` discriminates 171/8 — so the mechanism is sound and the constancy is this project's initialisation order, not a mechanism failure)
327
+ - Report the **count and the ID list**; a bare percentage hides whether the set is coherent
328
+
329
+ **Carrier test — what counts as "this FR's work is accounted for"**: a zero-`tasks.md`-reference FR is NOT automatically a gap. Check all three routes before reporting one, and **state in the evidence which route carries it**:
330
+
331
+ | Route | Carrier | Example |
332
+ |-------|---------|---------|
333
+ | Planned task | a `T-nnn` in `tasks.md` that references the FR | — |
334
+ | Test-layer delivery | an `IT/CE/AE` task in `specs/test-tasks.md` whose row/annotation names the FR | FR-027 → IT-009 `[x]` + CE-002 re-verify PASS |
335
+ | Fix-task delivery | an `FT-xxx` in `specs/fix-tasks.md` that delivered the behaviour | FR-027 → FT-020 (NewFBSize(-223) fix, real-peer driven) |
336
+
337
+ An FR with **none** of the three is a genuine coverage gap; an FR carried by route 2 or 3 is a **different, narrower** finding — typically a missing *unit* layer, which is reported as such (severity MEDIUM, routed per the table in "Finding Registration"). FR-027 is the worked instance: fully carried by routes 2+3, its only real gap being the unit layer.
338
+
339
+ #### G. Test-First Compliance Detection 🆕
340
+
341
+ **Purpose**: Verify Constitution Article IV (Risk-Based Quality Assurance) compliance
342
+
343
+ **Detection Rules**:
344
+ - **High-Risk Module Violations** (CRITICAL):
345
+ * Protocol implementations without test tasks before implementation tasks
346
+ * Cryptography/security modules without test tasks
347
+ * Network transport modules without test tasks
348
+ * ⚠️ **PRECONDITION — read this BEFORE the ordering rule below** (`T154` / `ISS-74` ②; user ruling 2026-09-20):
349
+ * **The ordering criterion only applies to projects whose verification is *pre-emptive*** — i.e. a **test suite** that can genuinely be written and run **before** the implementation exists (unit/integration tests against a spec).
350
+ * **It does NOT apply to a project whose verification is *post-hoc*** — where the check is a **command that verifies an artifact's existence or consistency** (`diff -rq` · a `grep` reverse-lookup · a verifier script that reads the produced file). ⚠️ **A command that verifies whether an artifact exists cannot be sequenced before that artifact is produced** — so on such a project this rule is **structurally unsatisfiable**, and reporting it as CRITICAL is a **false failure that blocks the pipeline**.
351
+ * **How to decide** — from the project's own material, not from taste: if the `[Quality]` tasks' verification commands are of the "**re-run this check on the artifact**" form, the project is post-hoc ⇒ **do not read the ordering; report this pass as `N/A` (with that one-line reason) instead of a verdict**.
352
+ * ⚠️ **Measured instance (this repository)**: `FR-002` is HIGH-RISK; its verification task `T033` sits **after** the implementation tasks `T018`/`T019` — by the letter of the rule that is CRITICAL, and `/specpro-implement`'s Step 2b **blocks** on CRITICAL.
353
+ * Check task ordering: Test tasks should appear before or alongside implementation tasks **— subject to the precondition above**
354
+
355
+ - **Medium-Risk Module Violations** (HIGH):
356
+ * Business logic without test tasks
357
+ * Data models/repositories without test tasks
358
+ * Platform API bindings without test tasks
359
+
360
+ - **Validation**:
361
+ * Map each implementation task to related test tasks
362
+ * Check if test task appears before implementation task in tasks.md
363
+ * Flag high-risk modules missing test coverage
364
+
365
+ **Example Detection**:
366
+ ```markdown
367
+ - FR-xxx "Wire Protocol Handler" (High-Risk: Protocol implementation)
368
+ Plan.md: Protocol handler implementation
369
+ Tasks.md: ❌ No test tasks found before implementation task
370
+ Constitution: Article IV requires Test-First for high-risk modules
371
+ Severity: CRITICAL
372
+ Recommendation: Add protocol handler test tasks before implementation
373
+ ```
374
+
375
+ #### H. Performance Metrics Loss Detection 🆕
376
+
377
+ **Purpose**: Ensure performance requirements from spec.md are preserved in plan.md and tasks.md
378
+
379
+ **Detection Rules**:
380
+ - Extract performance metrics from spec.md NFRs (e.g., "<500ms latency", "30-60 FPS")
381
+ - Check plan.md for performance design addressing these metrics
382
+ - Check tasks.md for performance-related tasks (profiling, optimization, benchmarking)
383
+ - **Severity**: HIGH if critical performance metrics missing from plan/tasks
384
+
385
+ **Example Detection**:
386
+ ```markdown
387
+ - NFR-xxx "Screen update latency < 500ms"
388
+ Spec.md: "<500ms end-to-end latency"
389
+ Plan.md: ⚠️ No performance strategy found
390
+ Tasks.md: ❌ No performance measurement tasks
391
+ Severity: HIGH
392
+ Recommendation: Add performance monitoring tasks to tasks.md
393
+ ```
394
+
395
+ #### I. Checklist Utilization Detection 🆕
396
+
397
+ **Purpose**: Verify that quality checklist findings are addressed in plan/tasks
398
+
399
+ **Detection Rules**:
400
+ - Load checklists/requirements.md if exists
401
+ - Extract the checklist's **own** fields — `**Status**: PASS|BLOCK` · `**Passed**` · `**Failed**` · per-item `**Status**: x|⊘ Skipped|✗ Failed`. ⚠️ 本节此前写的是 `Extract ❌ FAIL and ⚠️ WARNING items`(`T174`)—— **那两个字符串没有任何生产者**,而 `⚠️ WARNING` 这一档在模板里**根本不存在**(只有三种取值)⇒ 照它提取恒为空,而空读起来像「没有失败项」。
402
+ - For each `✗ Failed` item — ⚠️ **the set is the one the line above extracts**; `❌ FAIL`/`⚠️ WARNING` are not values this checklist can carry(`T174`):
403
+ * Search plan.md for design addressing the issue
404
+ * Search tasks.md for tasks addressing the issue
405
+ * Flag if unaddressed
406
+
407
+ **Example Detection**:
408
+ ```markdown
409
+ - Checklist: "Protocol implementation test-first" (`**Status**: ✗ Failed`)
410
+ Constitution: Article IV requires >90% test coverage
411
+ Plan.md: ⚠️ No test strategy found
412
+ Tasks.md: ⚠️ No test tasks for protocol modules
413
+ Severity: CRITICAL
414
+ Recommendation: Add test strategy to plan.md and test tasks to tasks.md
415
+ ```
416
+
417
+ #### J. Test Matrix Gap Detection 🆕
418
+
419
+ **Purpose**: Verify high-level test coverage (integration / component E2E / app E2E) is planned for the FR full set via `specs/test-tasks.md`
420
+
421
+ **Detection Rules**:
422
+ - **Matrix not built** (specs/test-tasks.md missing, MEDIUM):
423
+ * No coverage matrix exists for any FR
424
+ * Recommendation: Run `/specpro-test-plan` to generate the coverage matrix and high-level test tasks
425
+
426
+ - **Zero-coverage FRs** (apply ONLY to rows in execution states not-started/in-progress):
427
+ * FR appears in spec.md but has NO row in the coverage matrix (MEDIUM)
428
+ * FR has a matrix row but ALL of IT/CE/AE cells are empty/rationale-only with no task ID (HIGH if the FR belongs to a HIGH-RISK module per plan.md → CRITICAL; otherwise MEDIUM)
429
+ * ⚠️ Do NOT count planning-verdict rows as gaps: `pending-impl` (no implementation component — by design no tasks), `manual` (manual coverage via /specpro-manual-test), `not-applicable` (unit coverage sufficient), `deprecated` (FR deleted from spec)
430
+ * ⚠️ The `pending-impl` exemption applies ONLY to zero-coverage alerts within THIS Pass. Platform/feature-tier gaps *behind* a pending-impl row (e.g. the platform a full-tier FR claims has no registered build target at all) are NOT excused — Pass K surfaces them as grounding findings
431
+
432
+ - **Single-layer coverage of HIGH-RISK modules** (HIGH):
433
+ * Protocol / cryptography / network transport modules whose FRs have only unit coverage (tasks.md) and no integration (IT) or component E2E (CE) task
434
+ * These modules require at least one integration-level test per Constitution Article IV risk-based quality assurance
435
+
436
+ - **Cross-platform constraint anchored to a single-platform scenario** (HIGH):
437
+ * FR text claims "all platforms" / "cross-platform" / enumerates platforms (e.g. Android, iOS, Desktop), but its only covered cell is a scenario (AE/CE/IT) that exercises ONE platform
438
+ * A single-platform assembly scenario can never satisfy a multi-platform claim — the FR reads as covered while the unclaimed-in-test platforms stay invisible
439
+ * Recommendation: anchor the FR to a per-platform coverage set (one cell/scenario per claimed `full`-tier platform), or split the FR per platform
440
+
441
+ - **Stale matrix rows**:
442
+ * Matrix row references tasks that no longer exist in test-tasks.md, or FR IDs that no longer exist in spec.md (LOW)
443
+ * **Change-log staleness** 🆕 (MEDIUM): FR has SpecStatus = create/update in spec.md, but its most recent Matrix Change Log entry predates that spec change (or the FR has no change-log entry at all beyond the initial create) — the matrix has not re-processed a changed FR; the matrix is out of sync with the spec. Recommendation: run `/specpro-test-plan` (incremental mode re-processes exactly these change-log-drifted FRs)
444
+ * Tasks marked `[DELETED]` still physically present: informational only (removal happens on a later test-plan pass), NOT a finding by itself
445
+
446
+ **Example Detection**:
447
+ ```markdown
448
+ - FR-xxx "Wire Protocol Handler" (High-Risk: Protocol implementation)
449
+ test-tasks.md: ❌ No matrix row for FR-xxx
450
+ Severity: HIGH
451
+ Recommendation: Run /specpro-test-plan to register FR-xxx in the coverage matrix
452
+
453
+ - FR-xxx "Wire Protocol Handshake" (High-Risk: Protocol implementation)
454
+ Matrix: unit ✅ (tasks.md T-xxx), integration ❌ (no IT task), CE ❌ (no CE task)
455
+ Severity: HIGH - single-layer coverage for protocol module without integration test
456
+ Recommendation: Run /specpro-test-plan (incremental) to add IT/CE coverage
457
+
458
+ - FR-xxx "Connection Profile Management"
459
+ spec.md: SpecStatus=update (v1.1); Matrix Change Log: no FR-xxx entry after initial create
460
+ Severity: MEDIUM - matrix out of sync with spec (change-log staleness)
461
+ Recommendation: Run /specpro-test-plan (incremental) — its change-log-driven scope re-processes FR-xxx
462
+ ```
463
+
464
+ #### K. Platform Grounding Check 🆕
465
+
466
+ **Purpose**: Mechanically verify that every platform the planning artifacts CLAIM is actually grounded in the build — plan claims vs. registered build targets vs. source-set reality. Closes the class of gap where claims live in documents, builds live in code, and no gate cross-checks the two (the FR-xxx/FR-yyy mobile-gap class).
467
+
468
+ **Detection Steps** (mechanical; run ALL):
469
+
470
+ 1. **Extract claimed platforms** from plan.md Target Platform (+ any tier annotation). Per claimed platform record its tier: `full` (all features), `restricted` (basic feature set — the claim MUST cite the spec clause defining the boundary), `planned`/`deferred` (explicitly not current delivery). An unannotated claim defaults to `full`.
471
+
472
+ 2. **Extract grounded evidence** from the build:
473
+ * `settings.gradle.kts` `include(...)`: application module per platform (e.g. `:desktop-app`, `:android-app`, `:ios-app`)
474
+ * Per-module build scripts: registered compilation targets (`jvm()`, `androidTarget()`, `androidApplication`, `iosX64()`/`iosArm64()`/`iosSimulatorArm64()`, Kotlin/Native targets)
475
+ * Entry-product existence: `AndroidManifest.xml`, Xcode project / iOS app entry, desktop `main` entry
476
+ * Source-set census: platform source directories (`androidMain/`, `iosMain/`, ...) and whether they belong to a REGISTERED compilation target
477
+
478
+ 3. **Compare and report**:
479
+ * **Claimed `full` platform with no registered target / no app module / no entry product** (CRITICAL): the claim is invisible to every execution gate (compile, test, manual) — target registration is the precondition for any gate to see the platform at all. Matrix `pending-impl` status does NOT excuse this finding
480
+ * **Claimed `restricted` platform without a boundary clause** (HIGH): spec must define the restricted feature set (which FRs are in scope on that platform); task/contract text citing an unwritten constraint ("per <X> constraints" with no spec anchor) is evidence of this finding
481
+ * **Claimed platform neither grounded nor explicitly marked `planned`/`deferred`** (HIGH): undocumented claim — ground it, downgrade the claim, or annotate `deferred`
482
+ * **Orphan source sets** (HIGH): platform source files exist but belong to NO registered compilation target — dead code that silently passes every compile/test gate; any `[x]` on tasks that wrote such files is unverified
483
+ * **Tier coverage mismatch** (MEDIUM): FRs listed in a restricted-tier boundary clause but absent from the matrix (or vice versa)
484
+
485
+ **Example Detection**:
486
+ ```markdown
487
+ - plan.md Target Platform: "Android 5.0+ (full), iOS 12+ (full), Desktop (full)"
488
+ Build evidence: settings.gradle.kts includes `:desktop-app` only; core registers `jvm` target only;
489
+ core/src/androidMain (3 files) + core/src/iosMain (3 files) belong to NO registered target
490
+ Severity: CRITICAL — Android/iOS claimed full with zero grounding; 6 orphan source files
491
+ Recommendation: ground the claims (register targets + app modules) or restate the claim
492
+ (tier downgrade / `deferred` annotation); then re-verify the `[x]` state of platform-actual tasks
493
+ ```
494
+
495
+ #### L. Protocol Consistency Audit 🌐 [CONDITIONAL — wire-format / protocol modules only]
496
+
497
+ **Activation**: decided by the **Activation Gate** (`.specpro/templates/protocol-golden-bytes-guide.md` §6) — triggers T1–T5. Run alongside the other active passes (A–K, M, N, O) when the verdict is ACTIVE or ACTIVE-WITH-GAPS. A verdict of NOT-ACTIVE is itself audited by L6 rather than silently accepted.
498
+
499
+ - **L1 — Same-semantics branch scan**: detect byte-length / packing / stream-semantics branches duplicated across a decoder or encoder family. After a fix is applied to one such branch, its siblings MUST be scanned. Finding pattern: several functions in the same file carry same-semantics branches whose values disagree. (Historical shape: a decoder family carried N such branches; a fix touched N−1 and missed one, which stayed latent for months.)
500
+ - **L2 — Verification-method semantic audit**: whether the verification technique used by a protocol test matches the semantics of the stream under test. A one-shot full-buffer decode reporting `incomplete` against a continuous stream is a false-defect pattern; an `incomplete` / `truncated` verdict MUST first rule out a method-semantics mismatch.
501
+ - **L3 — Protocol-point coverage audit**: the field/branch-level protocol-point inventory (see `.specpro/templates/protocol-golden-bytes-guide.md` §1) checked point by point against test coverage. A low-frequency path (incremental small payloads, extension chains, non-divisible sizes) with no coverage is a finding.
502
+ - **L4 — Anchor-source audit**: golden bytes and expected test values MUST carry a source layer (specification / reference implementation / captured stream) plus the protocol version they were derived from. Unlabelled, or sourced from the implementation under test, is a finding — that is the self-confirming loop.
503
+ - **L5 — Peer-behaviour assertion audit**: every test expectation that asserts a peer behaves in a particular way MUST trace to a row in the Peer Diversity Registry in `specs/test-tasks.md`. An assertion with no registered row is a finding — unmeasured peer behaviour MUST NOT be frozen into an expectation. If the registry section is absent altogether, report it once as a single finding rather than per assertion.
504
+ - **L6 — Activation audit**: whether the Activation Gate (§6) was decided correctly and recorded. L1–L5 audit what happens *after* activation; none of them can see a stage that never activated — an unactivated stage produces no artifacts to audit, and the audit of its absence is indistinguishable from a feature with no protocol content. Detection:
505
+ * **Missed activation** (HIGH): the artifacts carry a gate trigger (T1–T5) but the stage that owns it recorded no verdict and produced no artifacts. The verdict is missing, not the trigger — re-derive the trigger mechanically from the artifact text and report the mismatch.
506
+ * **Unrecorded verdict** (MEDIUM): artifacts or gaps exist, but no verdict row (§6.4) — the work is not attributable and the next stage cannot consume it.
507
+ * **Verdict discrepancy across stages** (MEDIUM): one stage recorded NOT-ACTIVE while a later stage both found a trigger and produced artifacts, or the reverse. The later stage's silent override is the failure; either way the discrepancy is reportable.
508
+ * **Fabricated anchor** (HIGH, overlaps L4): an anchor annotated with a source layer it cannot have come from — in particular, a byte sequence present without any reachable source (a §6.3 GAP recorded as though covered). L4 catches "the implementation under test" as a source; L6 catches "no source at all, presented as anchored".
509
+ - See `.specpro/templates/protocol-golden-bytes-guide.md` §4 and §6 for the lateral-audit criteria and the activation verdict / GAP format in full.
510
+
511
+ #### M. Shared-Layer Boundary Audit 🌐 [CONDITIONAL — only when the constitution carries a shared-code / multiplatform / core-logic principle]
512
+
513
+ **Activation**: run alongside the other active passes (A–L, N, O) when the constitution contains a principle mandating that some category of code (business logic / core protocol / data model) live in a shared module. This pass exists because the constitution's shared-code mandate is otherwise unenforced: Pass D checks constitution *alignment* in prose, but a layered-architecture description names layers without saying which concrete source set each layer owns — so a module can sit in a platform-only source set while every artifact still reads as compliant.
514
+
515
+ **The failure shape** (why prose alignment never catches it): two components with the same architectural role land in different source sets, because placement follows whichever directory is nearest at implementation time. Nothing in the artifacts contradicts: the layer diagram still shows the component, the FRs are still covered, the tests still pass — the tests simply run on the one platform the code was placed for. The gap only becomes visible when a second platform tries to consume the layer.
516
+
517
+ **Detection — three mechanical checks**:
518
+
519
+ - **M1 — Shared-corpus gap** (CRITICAL): a code category the constitution mandates as shared is present ONLY in a platform-specific source set, with no equivalent in the shared set. Derive the mandated categories from the constitution's own wording; locate the corresponding packages; compare against the build's source-set registration. The requirement is not "the code exists somewhere" but "it lives in the corpus set" — a shared-mandated layer in a platform-only set is unreachable from the other platforms by construction.
520
+ - **M2 — Transport coupling of a shared layer** (CRITICAL): a shared-mandated handler's construction path requires a transport-layer object (a live socket, connection, session, or client holder) — i.e. it cannot be constructed without a real network. This is the mechanism behind a recurring false diagnosis: the coupling forces every verification end-to-end, end-to-end verification inherits timing coupling, and the resulting intermittent failures get attributed to test flakiness rather than to the missing independent-testability boundary.
521
+ - **M3 — Platform-capability leak into a shared layer** (CRITICAL): a shared-set file imports a platform-specific API (a platform dialect's I/O, compression, image, or crypto module) with no corresponding expect/actual declaration. The code compiles for the author's platform and fails only when a second platform is built — often on a machine the author is not running.
522
+ - **Declaration absent** (MEDIUM): the constitution carries a shared-code principle but plan.md has no Shared/Platform Boundary Declaration subsection, so M1–M3 have no declared boundary to check against. Report this once, not per check.
523
+
524
+ **Relationship to Pass K**: K compares *platform claims* against build target registration; M compares *shared-code claims* against source-set placement. They share the "claims live in documents, reality lives in the build" shape but audit different claim classes — a project can pass K and fail M.
525
+
526
+ **Not covered by this pass**: whether the placement is *desirable* (that is a design decision), and code that no constitutional principle claims as shared (its placement is free).
527
+
528
+ #### N. Contract-Fact Source Audit 🌐 [CONDITIONAL — only when `specs/contracts/` exists]
529
+
530
+ **Activation**: run alongside the other active passes (A–M, O) when the feature has contracts under `specs/contracts/`. This pass exists because a contract is the one artifact that is **read as authority but never itself verified**: an assertion inside it is not evaluated, it is copied. Downstream tests, implementations and reviews inherit its values. A wrong value therefore propagates with the full weight of a specification behind it — and, unlike a missing value, nothing prompts anyone to check it.
531
+
532
+ **The failure shape**: a contract value was wrong for an extended period, citing nothing; nothing reported it. The reader had no way to distinguish "read from an authoritative source" from "recalled". This generalises beyond protocol values — every asserted fact in a contract has this property.
533
+
534
+ **How to tell whether a fact is attributed** — attribution is an **inline marker immediately above the fact block** (per the contract content rules), not a collected sources section:
535
+
536
+ ```markdown
537
+ > Source: <L1 standard §<section> | L2 <implementation> <version> [<file/section>] | L3 <capture: peer + version>>
538
+ ```
539
+
540
+ | Observation | Verdict |
541
+ |-------------|---------|
542
+ | Marker directly above the fact block, resolving to a section or a versioned implementation | attributed — no finding |
543
+ | No marker above the block | **N1** |
544
+ | Marker present but names only the protocol, or a versionless implementation | **N1a** |
545
+ | Block attributed only by pointing at a sibling contract whose own blocks carry no markers | **N1b** |
546
+ | Prose, reasoning, design rationale, API signatures | not a fact — no marker needed, no finding |
547
+ | A `## Sources` / “fact sources” table at the end of the file | **not attribution** — it separates fact from source, which is where drift lives. Treat the facts it claims to cover as unattributed |
548
+
549
+ **Detection — the checks**:
550
+
551
+ - **N1 — Unattributed assertion** (HIGH): a contract states a fact about how the world is (a type code, field width, bit allocation, wire order, version-dependent behaviour, or an "is/is not supported" claim) with no source marker above it. The requirement is that the fact be checkable without trusting the author. A design choice (API signature, decomposition, naming, which codes this implementation advertises) needs no attribution — do not report those.
552
+ - **N1a — Attribution that does not resolve** (HIGH): an attribution is present but does not reach a checkable place. The common form is a **bare protocol name or version** — it identifies *which protocol*, not *which part of it* or *how it was read*; a reader given only that still has to re-derive the claim from the whole document. The attribution MUST resolve to a section of the standard, or to a named implementation **with its version**. A named implementation without a version is the same failure in a different costume: it cannot be checked against the version the claim was actually read from.
553
+ - **N1b — Unaudited cross-reference** (HIGH): the fact is sourced by pointing at another contract, but the referenced section does not itself carry resolving attributions. A cross-reference is a legitimate source **only when the referenced section is itself audited** — otherwise the chain merely relocates the unverified claim, and two contracts citing each other can appear fully sourced while nothing is resolved. Resolve the chain to its terminus; a terminus with no attribution is the finding.
554
+ - **N2 — Source cannot support the claim** (HIGH): the cited source, by its own nature, does not cover what is asserted — e.g. the base standard is cited for a sub-encoding layout the standard does not define. A standard citation for something the standard omits is not a stronger source; it is a wrong one. Where the standard is silent, the attribution MUST point at an authoritative implementation, named with its version.
555
+ - **N3 — Implementation as its own witness** (HIGH, overlaps L4): the fact is asserted from the implementing code under audit. The implementation cannot witness its own correctness — this is the self-confirming loop in contract clothing. Third-party sources only.
556
+ - **N4 — Unmeasured peer-behaviour claim** (HIGH, overlaps L5): a claim that a named peer requires, tolerates, or rejects something, with no measured row in the Peer Diversity Registry. Such an item MUST be recorded as unverified rather than asserted.
557
+
558
+ **Discrimination note**: N1 must compare **value and semantic label together**, not value alone. A contract entry and the implementation can agree on a number while disagreeing on what it means — the same numeric code labelled as one encoding in the contract and a different one in the code. A pure numeric diff misses exactly this, and it is the most dangerous variant: the value looks confirmed.
559
+
560
+ **Relationship to adjacent passes**: L4/L5 are the protocol-scoped versions of N3/N4; N applies to any contract asserting external facts. Pass F checks whether artifacts *agree with each other*; N checks whether an assertion is *right*, and whether its reader has any way to find out. Pass M compares shared-code claims against source-set placement; N compares asserted facts against their cited sources.
561
+
562
+ **Where findings go**: this pass reports only — it does not edit contracts. Register contract findings in the `[plan]` section of `specs/implement_issues.md`; `/specpro-plan --review-issues` owns `specs/contracts/` and applies the corrections, because a contract is a plan-phase artifact and its source attributions are resolved against the spec's lifecycle state. Reporting a contract finding without a route leaves the artifact stating a value the audit has already shown to be unsupported.
563
+
564
+ **Not covered**: design choices (no external fact to source), and whether a correctly-attributed value is *desirable*.
565
+
566
+ #### O. Anti-Coupling Scan
567
+
568
+ **Activation**: run alongside the other active passes (A–N) on **every** analysis. Unlike L/M/N this pass has no activation condition: the coupling it looks for can be introduced by any edit, and the editor is precisely the party who cannot see it.
569
+
570
+ **What it looks for**: specpro's own distributed assets (`commands/` · `templates/` · `scripts/`) carrying traces of the **host project** they were first developed against. Those assets ship to every user, so a host-specific trace ships with them.
571
+
572
+ **Coverage — three classes, and all three are required.** A scan covering two of them is not "partial credit"; the uncovered class is the finding:
573
+
574
+ - **Numeric identifiers** — an `FR-` / `T` / `ISS-` / `D-` identifier and its siblings. ⚠️ **Written here as the prefix form, never as a real identifier**: a rule that forbids identifiers in shipped assets would itself be an instance of the leak if it demonstrated the form with one — the same self-reference trap as a keyword table that lists a keyword it must not match. ⚠️ An identifier means nothing outside the repository that allocated it, so a reference to one is a reference to a document the reader does not have.
575
+ - **Host technology stack** — framework, language, tool and build-plugin names, **with versions**. A pinned version is specific to one project's stack even when the technology is not.
576
+ - **Host module and class names** — the project's own source paths, package names, and type names.
577
+
578
+ ⚠️ **All three are scoped to the HOST project.** specpro citing its own requirements and its own modules is provenance; citing another project's is leakage.
579
+
580
+ ⚠️ Constitution clause 1.3 names "*module names, package names, platform names, business terms*". That enumerates the **third** class plus the bare project name, and stops there. The first two classes are in scope **because they leak the same way and nothing else catches them** — which is exactly why the enumeration, not the clause, is the part that has to be maintained.
581
+
582
+ **Cases enter as SHAPES, never as instances — in ALL THREE classes** (FR-053). ⚠️ **The scope is the whole pass, not the first class** (`T179` / `ISS-123`, 形态 10「一般规则只以实例形式存在」): each class entry above ends in a prohibition, and **a prohibition demonstrated with an instance of what it forbids is itself an instance of it** — an identifier rule that quotes a real identifier, a stack rule that names a pinned framework, a module rule that names a class. Measured: the two implementations of this scan once carried the same sentence twice — one wrote the **rule** ("a hardcoded host term here would BE the leak it exists to find"), the other wrote the **instance** (the actual terms) — and **only the instance-bearing side was itself a leak, while the scan caught it**. The mechanism worked; the rule was under-scoped. ⇒ State each rule so the next instance is recognisable *by shape*: *"N same-shaped branches in a family, a fix touching N−1, latent for months"* is usable; *"the defect at <that one issue>"* is not — and mechanically substituting a placeholder for the value deletes the shape along with it. **The transferable part is the shape, not the example.**
583
+
584
+ **The pattern table is a maintained asset, not a one-off script.** When a host-specific trace is found, the fix has **two** halves: remove the trace, **and** add the pattern that would have caught it. Without the second half the same class re-enters on the next edit.
585
+
586
+ **Execution** ⚠️ [settled 2026-09-18]: run `.specpro/scripts/bash/check-anti-coupling.sh` from the repository root. It prints its hits by class and exits non-zero when it finds any; hits are **file-level**, so locating the line is the running step's job when filling the table below. The three classes are covered by **two different mechanisms**, and the difference decides what "maintaining the table" means for each:
587
+
588
+ - **Class 1 (identifiers) is DERIVED, never listed.** "Foreign" means "not allocated by this project", and a project already records its own numbers — so the scan reads each prefix's range from the artifact that **allocates** it. ⚠️ It must not read the range from every artifact that *mentions* it: a file that quotes foreign identifiers while instructing their removal feeds its own maximum back into the measurement, and a range that has absorbed the very identifiers it should catch is blind. The measurer must not be fed the thing being measured.
589
+ - **Classes 2 and 3 are patterns, and the patterns live in `specs/anti-coupling-patterns.txt`** — a PROJECT artifact, deliberately outside the distributed assets. It names the host project's stack and domain terms, which is exactly what this pass forbids *inside* `commands/` `templates/` `scripts/`; a shipped file carrying those strings would itself be the leak it exists to find. The scanner reads them from there, so nothing under `scripts/` knows them.
590
+
591
+ ⚠️ **A class with no patterns is a finding, not a skip.** Pass O requires all three, so the scan fails when a class has no patterns — including when the table is absent altogether — rather than reporting the two it managed to check. A project adopting this pass creates its own table; until it does, the scan names the uncovered class instead of passing silently.
592
+
593
+ ⚠️ **A pattern earns its place by a measurement, and the scan must be seen to fail.** A pattern that nothing in the assets matches is how a table grows decorative, so add one only on a real hit. And a scan that has only ever reported clean is indistinguishable from one that cannot report anything: put a known trace back into a shipped asset and confirm the scan names it — the same discipline Pass L6 applies to its own assertions.
594
+
595
+ **Findings**:
596
+ - **O1 — Foreign numeric identifier in a distributed asset** (HIGH): an `FR-` / `T` / `ISS-` / `D-` identifier **belonging to a project other than specpro itself** appears in a shipped file.
597
+ ⚠️ **The scoping word is "foreign", and the first application of this rule is why.** A bare "any identifier" formulation also flags specpro's **own** requirement citations (`FR-053` and friends), which are **provenance, not leakage**: they say which requirement an instruction implements, resolvable by anyone holding the tool's own spec, and meaningless-to-a-user in a way that is harmless. Constitution clause 1.3 draws the same line — it forbids *the host project's* concrete names.
598
+ **The judging question**: *whose specification defines this number?* If it is not specpro's, the reader cannot resolve it from anything they received. A number above this document's own range is the mechanical tell; an identifier that is in range but carries a **host-specific gloss** ("FR-027 is the worked instance: …") is the one that needs a reader to notice.
599
+ - **O2 — Host technology stack named in a distributed asset** (HIGH): a framework, language or tool name with a version, or a build-plugin name, appears in a shipped file.
600
+ - **O3 — Host module or class name in a distributed asset** (HIGH): a path, package or type name belonging to the host project appears in a shipped file.
601
+ - **O4 — Case recorded by identifier instead of by shape** (MEDIUM): a rule whose value is its transferability is stated via an identifier, so it cannot be applied anywhere else.
602
+
603
+ **Where findings go**: this pass **reports only** — it does not edit the assets. The fix is a tool-source change, so register in the `[tasks]` section of `specs/implement_issues.md`. A finding registered without a route is indistinguishable from one never reported.
604
+
605
+ **Not covered**: host content that is not a trace. The assets may legitimately describe the host project's *conventions* in abstract terms ("when a shared layer depends on a platform capability…"); what is forbidden is naming the concrete project.
606
+
607
+ **Relationship to adjacent passes**: Pass D checks the assets against the constitution *in prose*; this pass checks whether the assets carry a **different project's fingerprint**. Clause 1.3 is the rule; this pass is its enumeration — and the enumeration is what was incomplete.
608
+
609
+ ### 5. Severity Assignment
610
+
611
+ Use this heuristic to prioritize findings:
612
+
613
+ - **CRITICAL**: Violates constitution MUST, missing core spec artifact, or requirement with zero coverage that blocks baseline functionality, Test-First violations for high-risk modules, zero-coverage HIGH-RISK-module FRs in the test matrix (Pass J), platform claimed `full` with zero build grounding (Pass K), constitution-mandated shared code present only in a platform-specific source set (Pass M1), a shared-mandated handler whose construction requires a live network object (Pass M2), a platform-specific API imported into a shared layer with no expect/actual declaration (Pass M3)
614
+ - **HIGH**: Duplicate or conflicting requirement, ambiguous security/performance attribute, untestable acceptance criterion, Test-First violations for medium-risk modules, performance metrics loss, unaddressed checklist FAIL items, zero-coverage FRs or single-layer coverage of protocol/crypto/network modules in the test matrix (Pass J), an FR with **zero task coverage and no carrier on any of Pass F's three routes** — its delivery is unaccounted for (Pass E), cross-platform constraint anchored to a single-platform scenario (Pass J), orphan platform source sets / undocumented platform claims / `restricted` tier missing boundary clause (Pass K), same-semantics branch duplicated across a codec family with a sibling left unfixed (Pass L1), spec anchor sourced from the implementation under test or carrying no source-layer annotation (Pass L4), a contract stating a fact about how the world is with no source layer and version, citing a source that cannot cover the claim, asserting the fact from the implementing code itself, or claiming peer behaviour with no measured registry row (Pass N1–N4), gate trigger present but activation never recorded and no artifacts produced — missed activation, or a byte sequence presented as anchored with no reachable source (Pass L6), a numeric identifier, a pinned technology name, or a host module/class name present in a distributed asset (Pass O1–O3 — it ships to every user and is meaningless in the next repository)
615
+ - **MEDIUM**: Terminology drift, missing non-functional task coverage, underspecified edge case, test matrix not built / FRs missing from matrix / zero-coverage LOW-or-MEDIUM-risk FRs / change-log staleness (matrix out of sync with spec SpecStatus changes) (Pass J), an FR carried by a test-layer or fix-task route but lacking its **unit** layer (Pass E/F — the narrow finding, not a coverage hole), a Lifecycle field that is `processed` on **every** item and therefore carries no information while downstream logic filters on it (Pass F), verification method mismatched to the semantics of the stream under test (Pass L2), protocol point with no test coverage (Pass L3), peer-behaviour assertion with no entry in the Peer Diversity Registry (Pass L5), activation verdict unrecorded for a stage that has protocol rules (the criterion is `.specpro/templates/protocol-golden-bytes-guide.md` §6.4 — *“A stage with protocol rules and no verdict row is a finding regardless of whether the artifacts happen to exist.”*; ⚠️ **the artifact's existence is not a premise of the finding** — reading it as one narrowed the criterion to stages that had already produced artifacts, which is precisely the stage that no longer needs the check), or a verdict discrepancy across stages — one stage NOT-ACTIVE while another produced protocol artifacts (Pass L6, the two non-HIGH verdicts), a shared-code constitution principle with no Shared/Platform Boundary Declaration in plan.md, leaving the boundary unauditable (Pass M)
616
+ ⚠️ **这里此前有两条相邻的 `**MEDIUM**:` 条目,第二条是第一条的真子集**(`T207` / `ISS-167`,2026-09-19 删除)。删的是**短的那条**,判据不是长度 —— 三条它缺的子句**各自在别处有承载**,逐条核过:**Pass E/F 的窄发现**在 §4 的 Pass E 里整条写着(含严重度与 FR-027 那个实例);**Pass F 的「恒定字段」**在同节的 stale-data 观察里、并在 Finding Registration 的路由表里有一行;**Pass M 的边界声明**在 Pass M 自己的表里。⇒ **删掉短的不会丢任何东西,删掉长的会丢一处**。⚠️ 两份并存的代价不是难看:`T185` 改的那个短语**在两条里各出现一次**,只改一条会让它的核验在两轮之间读数为非零 —— 同一事实的第二个来源,已分叉,而分叉不报错(宪法 Q2)。
617
+ - **LOW**: Style/wording improvements, minor redundancy not affecting execution order, stale matrix rows (dangling task/FR references) (Pass J)
618
+
619
+ ### 6. Report Generation ✨ ENHANCED with multiple modes
620
+
621
+ **Report Mode Selection**:
622
+ - If SUMMARY_MODE=true: Generate summary report only
623
+ - Else (default): Generate detailed report
624
+
625
+ **缺陷状态的表述规则** ⚠️ [FR-050 —— 本段在两个命令里**逐字相同**(`specpro.status.md` · `specpro.analyze.md`);改一处 MUST 同轮改另一处,否则它就是它所防的那种分叉(形态 3)]
626
+
627
+ **任何「有没有缺陷」的陈述 MUST 表述为「无已知缺陷」,MUST NOT 表述为「无缺陷」。** 两者是不同的断言,只有前者可核验:
628
+
629
+ | 表述 | 它声称什么 | 可否核验 |
630
+ |---|---|---|
631
+ | **无已知缺陷** | **登记表中每一个形态都已对它跑过检出,且已知实例为零** | ✅ 可核验 —— 重跑检出即得结论 |
632
+ | **无缺陷** | 一个关于**未被检视的那一部分**的断言 | ❌ 不可核验 —— 没有人对它做过测量 |
633
+
634
+ **定义即判据**:只有当**每一个形态都已被检出过**(没有一个落 `⊘`)**且命中数为零**时,才可以表述为「无已知缺陷」;否则 MUST 写出未检视的那部分。
635
+
636
+ ⚠️ **MUST 随附覆盖声明**:任何缺陷状态陈述 MUST 声明**所覆盖的范围** —— 哪些形态检出过、哪些**没能检出**(`⊘`)。⚠️ **「没有提到」与「没有欠账」是两句不同的话,而前者与「忘了看」无从区分**(`FR-036` 对覆盖主张施加的是同一条纪律:**声称通过而基线未覆盖,不构成通过**)。
637
+
638
+ ⚠️ **工具侧报告用英文,同一断言照此对应**:`no known instance` ✅ / `no defects` · `defect-free` ❌。两个形态说的是**同一件事**,只在语言上不同 —— 若只钉住中文那一侧,英文报告会**照旧声称「无缺陷」而没有任何东西报错**(形态 3)。
639
+
640
+ **机制(可复跑的形态)**:`scripts/bash/verify-shapes.sh`(PowerShell 对等:`scripts/powershell/verify-shapes.ps1`)就是这条判据的载体 —— 收尾报告给出 `N hit`(已知实例数)与 `M not executable`(没跑起来的组数)。**命中数不为零 ⇒ 不得表述为「无已知缺陷」;有 `⊘` ⇒ MUST 连带声明那一部分未证实,而不是干净。**
641
+
642
+ #### Summary Report Mode (if --summary flag present)
643
+
644
+ ```markdown
645
+
646
+ #### P. Feature Registry Consistency 🆕 [v0.23 · FR-018]
647
+
648
+ **Purpose**: 检出 feature 登记文件与磁盘目录的**双向不一致**与缺件。Consumers: 路由表(`[tasks]` — 实现修复归任务)。
649
+
650
+ - **P1 在册无目录**(MEDIUM): `specs/features.md` 含 `fNNN` 行,但 `specs/fNNN-*/` 目录不存在 → 登记失真,状态总览会漏报
651
+ - **P2 有目录未在册**(MEDIUM): `specs/f[0-9][0-9][0-9]-*/` 目录存在但登记文件无对应行 → 目录游离,进度/缺件对它不可见
652
+ - **P3 缺件**(MEDIUM): 目录内缺 `spec.md`/`plan.md`/`tasks.md` 任一项 → 列出缺失项(对照 FR-016 链路)
653
+ - **P4 status 越值**(LOW): 登记行 `status` ∉ {`active`, `delivered`, `deprecated`} → 字段取值漂移
654
+
655
+ **检出方式**(可复跑): 以 `specs/features.md` 的行集合与 `specs/` 下 `f[0-9][0-9][0-9]-*` 目录集合做双向 diff;目录内按三产物存在性核缺件。
656
+
657
+ ## 📊 Analysis Summary
658
+
659
+ **Quality** (from the checklist): [**Status**: PASS|BLOCK] — [N/M passed] ← 取清单真实的两个字段,不取一个它从不产出的「分数」
660
+ **Ready for Implement**: ✅ Yes | ⚠️ Warnings | ❌ No
661
+
662
+ **Critical Issues**: N
663
+ **High Issues**: N
664
+ **Medium Issues**: N
665
+ **Low Issues**: N
666
+
667
+ **Coverage**: X% (Y of Z requirements have tasks)
668
+
669
+ **Recommendation**: [PROCEED | FIX CRITICAL | ADDRESS WARNINGS]
670
+
671
+ **Defect status** (FR-050 — the wording rule above): [**无已知缺陷** — <N> shapes all exercised, 0 hits
672
+ | <N> known instance(s)
673
+ | ⚠️ **coverage incomplete** — <M> shape(s) could not be exercised at all, so that part is
674
+ **unproven, NOT clean**]
675
+ ⚠️ May be written as 「无已知缺陷」 **only** when every shape was exercised AND hits = 0. `Total Issues: 0`
676
+ here is a count of findings **on the artifacts**, not a statement about the tool's defects — the two are
677
+ different claims and only the second has a coverage declaration behind it.
678
+
679
+ **Next Steps**:
680
+ [Top 3 recommended actions]
681
+ ```
682
+
683
+ #### Detailed Report Mode (default)
684
+
685
+ ```markdown
686
+ ## 🔍 Specification Analysis Report
687
+
688
+ **Generated**: [Timestamp]
689
+ **Analysis Mode**: [Full | Incremental]
690
+ **Artifacts Analyzed**: spec.md, plan.md, tasks.md, constitution.md
691
+
692
+ **Executive Summary**:
693
+ - Total Issues: N (CRITICAL: M, HIGH: P, MEDIUM: Q, LOW: R)
694
+ - Coverage: X% (Y of Z requirements have tasks)
695
+ - Constitution Violations: N
696
+ - Test-First Violations: N (High-Risk: M, Medium-Risk: P)
697
+ - Test Matrix Gaps: N (zero-coverage FRs: M, matrix not built: yes/no)
698
+
699
+ ---
700
+
701
+ ### Findings Table
702
+
703
+ | ID | Category | Severity | Location(s) | Summary | Recommendation |
704
+ |----|----------|----------|-------------|---------|----------------|
705
+ | A1 | Duplication | HIGH | spec.md:L120-134 | Two similar requirements ... | Merge phrasing; keep clearer version |
706
+ | G1 | Test-First | CRITICAL | tasks.md:L45-50 | Protocol handler missing test tasks | Add test tasks before implementation |
707
+
708
+ (Add one row per finding; generate stable IDs prefixed by category initial.)
709
+
710
+ ---
711
+
712
+ ### Task Coverage Summary Table
713
+
714
+ **Dimension: TASK coverage — measured on `tasks.md`** ⚠️. Every row is decided by whether `tasks.md` carries the FR, not by the matrix (that is the next-but-one table's job, measured on `specs/test-tasks.md`) and **not** by `spec.md`'s `[tasks:processed]` field, which is wholesale-seeded and constant across all items — see Pass E's legacy caveat. When an FR shows "No", run Pass F's **carrier test** before calling it a gap and record which route carries it.
715
+
716
+ | Requirement Key | Has Task? | Task IDs | Carried by (if no task) | Notes |
717
+ |-----------------|-----------|----------|-------------------------|-------|
718
+ | user-upload-file | ✅ Yes | T-xxx, T-yyy | — | Well covered |
719
+ | FR-027 resolution-change | ❌ No | - | IT-009 + CE-002 (test-tasks.md) · FT-020 (fix-tasks.md) | Carried by routes 2+3 → unit layer only |
720
+
721
+ ---
722
+
723
+ ### Test-First Compliance Analysis 🆕
724
+
725
+ | Module | Risk Level | Test Tasks | Implementation Tasks | Status |
726
+ |--------|------------|------------|----------------------|--------|
727
+ | Wire Protocol Handler | High | 0 | 3 | ❌ CRITICAL - Missing tests |
728
+ | Crypto Module | High | 2 | 2 | ✅ PASS - Tests before implementation |
729
+ | User Repository | Medium | 0 | 1 | ⚠️ HIGH - Recommended tests |
730
+
731
+ ---
732
+
733
+ ### Test Matrix Gap Analysis 🆕
734
+
735
+ **Dimension: TEST-MATRIX coverage — measured on `specs/test-tasks.md`** ⚠️. A clean matrix (`168/168 rows`) is **not** evidence about task coverage — the two were measured 100% vs 52% on 2026-09-10. State the artifact in any finding derived from this table.
736
+
737
+ <!-- Render only when specs/test-tasks.md exists; otherwise emit one row:
738
+ "Matrix | - | - | - | ⚠️ MEDIUM - not built | Run /specpro-test-plan" -->
739
+
740
+ | FR | Risk Level | Unit | IT | CE | AE | Status |
741
+ |----|------------|------|----|----|----|--------|
742
+ | FR-xxx Wire Protocol Handshake | High | tasks.md T-xxx | IT-001 ✅ | ❌ none | AE-001 | ⚠️ HIGH - no component E2E |
743
+ | FR-xxx Decode Flow | High | core/src XxxDecoderTest | IT-002 ✅ | ❌ none | ❌ none | 🟡 MEDIUM - IT covered, no CE/AE |
744
+ <!-- ⚠️ 本行此前写的是 `🔴 CRITICAL`,而**它自己的规则**说:只有「**全部** IT/CE/AE 格都为空」
745
+ 且该 FR 属 HIGH-RISK 才是 CRITICAL,**否则 MEDIUM**(`T174`)。这一行的 IT 格是 `IT-002 ✅`
746
+ —— **不是全空** ⇒ 按规则就是 MEDIUM。示例与规则相反,而示例是照抄者会跟的那一个。 -->
747
+ | FR-xxx UI Layout | Low | - (pure UI) | - (pure UI) | - (app-level) | AE-003 | ✅ Covered (rationale documented) |
748
+
749
+ ---
750
+
751
+ ### Performance Metrics Tracking 🆕
752
+
753
+ | Performance Requirement | Plan.md | Tasks.md | Status |
754
+ |-------------------------|---------|----------|--------|
755
+ | <500ms latency | ✅ Addressed | ❌ No measurement tasks | ⚠️ HIGH |
756
+
757
+ ---
758
+
759
+ ### Protocol Consistency Analysis 🆕 (Pass L — render only when activated)
760
+
761
+ | Check | Finding | Location | Status |
762
+ |-------|---------|----------|--------|
763
+ | L1 Same-semantics branches | Same-shaped byte-counting branch appears in N functions; a fix touched N−1 | `XxxCodec.kt:L120, L204, …` | 🔴 HIGH - 1 branch unfixed |
764
+ | L2 Verification-method semantics | Continuous stream verified with a one-shot full-buffer decode | `XxxTest.kt:L88` | ⚠️ MEDIUM - false-defect risk |
765
+ | L3 Protocol-point coverage | Extension-chain path has no test case | inventory §1, row 2 | ⚠️ MEDIUM - low-frequency path uncovered |
766
+ | L4 Anchor source | Expected bytes derived from the implementation under test, no source layer | `XxxTest.kt:L41` | 🔴 HIGH - self-confirming loop |
767
+ | L5 Peer-behaviour assertion | Test expects a peer quirk that has no row in Peer Diversity Registry | `XxxTest.kt:L112` | ⚠️ MEDIUM - unmeasured behaviour frozen into expectation |
768
+ | L6 Activation verdict | Gate trigger present (T3: codec source) but no verdict row and no inventory/anchors produced | `plan.md` design section | 🔴 HIGH - missed activation, audit cannot see the stage |
769
+
770
+ ---
771
+
772
+ ### Shared-Layer Boundary Analysis 🆕 (Pass M — render only when the constitution carries a shared-code principle)
773
+
774
+ | Check | Finding | Location | Status |
775
+ |-------|---------|----------|--------|
776
+ | M1 Shared-corpus gap | Constitution mandates the protocol layer shared; it exists only in a platform-specific source set | `core/src/jvmMain/.../protocol/` | 🔴 HIGH - unreachable from other platforms by construction |
777
+ | M2 Transport coupling | Handler's construction requires a live connection object; cannot be built without a real network | `XxxDecoder.kt:L33` | 🔴 HIGH - forces end-to-end verification, timing coupling misread as flakiness |
778
+ | M3 Platform-capability leak | Shared-set file imports a platform-specific compression/image API with no expect/actual | `XxxCodec.kt:L12` | 🔴 HIGH - compiles for one platform, fails on the next build |
779
+ | M4 Declaration absent | Shared-code principle present, no Shared/Platform Boundary Declaration in plan.md | `plan.md` Architecture | ⚠️ MEDIUM - boundary unauditable |
780
+
781
+ ---
782
+
783
+ ### Contract-Fact Source Analysis 🆕 (Pass N — render only when specs/contracts/ exists)
784
+
785
+ | Check | Finding | Location | Status |
786
+ |-------|---------|----------|--------|
787
+ | N1 Unattributed assertion | Contract states a type code / bit allocation / wire order with no source layer and version; the reader cannot check it without trusting the author | `contracts/xxx.md:L88` | 🔴 HIGH - unchecked fact reads as authority |
788
+ | N1a Attribution does not resolve | Attribution names only the protocol (or an unversioned implementation), so the reader still has to re-derive the claim | `contracts/xxx.md:L90` | 🔴 HIGH - attribution present but hollow |
789
+ | N1b Unaudited cross-reference | Fact sources a sibling contract that carries no resolving attributions — the chain relocates the claim instead of resolving it | `contracts/xxx.md:L94` | 🔴 HIGH - apparent source, no terminus |
790
+ | N2 Source cannot support the claim | Base standard cited for a sub-encoding layout the standard does not define | `contracts/xxx.md:L92` | 🔴 HIGH - wrong source is not a weaker source |
791
+ | N3 Implementation as its own witness | Fact asserted from the implementing code under audit | `contracts/xxx.md:L96` | 🔴 HIGH - self-confirming loop |
792
+ | N4 Unmeasured peer-behaviour claim | "Peer X requires/rejects Y" with no measured row in the Peer Diversity Registry | `contracts/xxx.md:L101` | 🔴 HIGH - unmeasured behaviour asserted as fact |
793
+
794
+ ---
795
+
796
+ ### Anti-Coupling Analysis (Pass O)
797
+
798
+ | Check | Finding | Location | Status |
799
+ |-------|---------|----------|--------|
800
+ | O1 Numeric identifier | A shipped asset references `FR-…` / `T…` / `ISS-…`; a reader in another repository cannot resolve it | `commands/xxx.md:L42` | 🔴 HIGH - ships to every user |
801
+ | O2 Host technology stack | A framework/language/tool name with a version, or a build-plugin name, in a shipped asset | `templates/xxx.md:L17` | 🔴 HIGH - one project's stack, everyone's copy |
802
+ | O3 Host module or class | A host project path, package or type name in a shipped asset | `scripts/xxx.sh:L88` | 🔴 HIGH - another project's fingerprint |
803
+ | O4 Case by identifier | A rule whose value is transferability is stated via an identifier, so it cannot be applied elsewhere | `commands/xxx.md:L120` | 🟡 MEDIUM - the shape is lost with the number |
804
+
805
+ ---
806
+
807
+ ### Constitution Alignment Issues
808
+
809
+ [List any constitution MUST violations with article references]
810
+
811
+ ---
812
+
813
+ ### Unmapped Tasks
814
+
815
+ [List tasks with no clear requirement/story mapping]
816
+
817
+ ---
818
+
819
+ ### Detailed Metrics
820
+
821
+ **Requirements**: Total | Functional | Non-Functional
822
+ **Tasks**: Total | By Phase (Setup, Tests, Core, Integration, Polish)
823
+ **Coverage**: X% (requirements with >=1 task)
824
+ **Ambiguity Count**: N vague adjectives, N placeholders
825
+ **Duplication Count**: N near-duplicates
826
+ **Critical Issues Count**: N
827
+ **Constitution Violations**: N
828
+ **Test-First Violations**: N (High-Risk: M, Medium-Risk: P)
829
+ **Test Matrix Gaps**: N (zero-coverage FRs: M, single-layer HIGH-RISK modules: K, matrix not built: yes/no)
830
+ ```
831
+
832
+ ### 7. Finding Registration 🆕 (write, but ONLY the issue file)
833
+
834
+ **Naming gate — before you invent an identifier or a location** ⚠️ (FR-054): look it up first in the **existing** vocabulary. "Existing" means a table that is already there, not one this run invents.
835
+
836
+ **The test is wiring, not style.** An identifier outside the vocabulary has **no channel, no consumer and no check**: a requirement nobody can dispatch (no `--review-issues` recognises the number), a parameter nobody implemented, a location nobody reads. That three-part shape is not introduced here — it is the same invariant the ledger contract states for its sections (`specs/contracts/ledger.md` → `## Sections and their consumers`), and it is **FR-021's vocabulary discipline applied to every identifier and location**, including this design's own numbering (`FR-` / `T` / `ISS-` / `D-`).
837
+
838
+ ⚠️ **Scope note**: the gate for *defect shapes* is Step 1 of the routing rules below; this paragraph is its **general form**. A rule that exists only as one instance is not a rule — the next identifier invented somewhere else will not be seen by it.
839
+
840
+ ⚠️ **Each vocabulary table states its own channel, consumer and check; this paragraph deliberately does not restate them.** A restatement is a second source, and two sources of one fact diverge without reporting.
841
+
842
+ **The mechanical check** (Constraint 9 ①): `grep` the identifier against the table that would own it. **No hit means you are not naming it — you are inventing a channel**, and an invented channel has no consumer. The act is then **"extend that table"**, not "write the name here" — and the extension MUST land with its channel, consumer and check **in the same round**.
843
+
844
+ **Why this step exists**: a report is transient — it lives in the terminal and is gone when the session ends.
845
+ - **Tool defects route through the ledger, not a side registry** ⚠️ [T089 · FR-023]: if the defect you found is in **specpro itself** (this project's command documents, templates, or support scripts — when a project bootstraps specpro, those **are** the project's product), route it by ONE criterion: **does spec.md already demand the corrected behavior?**
846
+ 1. **Not demanded yet** → establish the requirement FIRST: register a `[specify]` entry naming the tool-source file and the missing requirement. `/specpro-specify --review-issues` amends spec.md; the fix then flows down the chain ([plan] → [tasks]) and returns as an executable task. Bypassing the requirement layer produces a task backed by no requirement — and a task with no requirement behind it cannot be verified against anything.
847
+ 2. **Already demanded** → the requirement exists and the tool fails it: register a `[tasks]` entry naming the tool-source file. `/specpro-implement` discharges it by executing a task whose Location names that file — the same single entry tool source has always had.
848
+ - **Why no side registry** ⚠️: a defect written to a file no command consumes is indistinguishable from one never reported (FR-023 — a record only human convention reads does not satisfy routing). The former side registry was absorbed into the spec chain and deleted (`T089`); where history needs its entry IDs, cite them as 「原 TOOL-0NN」 — a historical label, never a live pointer.
849
+ The only artifact the next stage can actually consume is an entry in `specs/implement_issues.md`. Without this step the loop is referenced but not wired: Pass N tells the reader to register contract findings in `[plan]`, `/specpro-plan --review-issues` reads that section, and no step in this command writes it. The conversion then happens by hand (or not at all), and each manual transcription is a place where a finding's specifics are lost.
850
+
851
+ **Scope — what this step writes, and what it must not touch**:
852
+
853
+ | Writes | Never writes |
854
+ |--------|--------------|
855
+ | `specs/implement_issues.md` — append entries, update the statistics table (**its own row only** — seven commands declare this artifact) | `spec.md`, `plan.md`, `tasks.md`, `specs/contracts/**`, any source file |
856
+
857
+ This is the **single exception** to this command's read-only default, and it is deliberately narrow: analysis may record what it found; changing the artifacts stays with the stage that owns them. If a finding needs an artifact change, that change happens when the owning `--review-issues` run consumes the entry — not here.
858
+
859
+ **Which findings get registered**:
860
+
861
+ - Register **CRITICAL / HIGH / MEDIUM**. Do not register LOW (style, minor redundancy) — it would dilute the queue.
862
+ - **Deduplicate — two separate checks, both required**:
863
+ 1. *Content*: scan the target section for an existing entry naming the same artifact + location + shape. If one exists (pending or resolved), **do not add a duplicate** — this keeps repeated `analyze` runs idempotent. If the finding is the same shape at a new location, extend the existing entry rather than opening a second one.
864
+ 2. *Identifier*: scan the **whole file**, not just the target section, for the highest `ISS-NNN` in use, and allocate the next free number. Sections are appended concurrently by more than one workflow — an ID that is free in your target section may already be taken elsewhere in the same file, and a collision silently merges two unrelated findings under one number.
865
+
866
+ A run that skips check 2 produces exactly the failure this step exists to prevent: the new entry looks registered, but a later `--review-issues` pass will match the number against the wrong finding.
867
+ - **Skip already-registered situations**: a finding that merely restates an existing pending entry's subject is not new information. A finding whose root cause is already covered by an entry should be noted inside that entry, not registered separately.
868
+
869
+ **Routing — by which stage owns the fix**, not by which pass emitted the finding.
870
+
871
+ ⚠️ **This table is the SINGLE SOURCE OF TRUTH for that routing decision** (FR-055). Other
872
+ artifacts reference it; none restates it. A restatement is a second source, and two
873
+ sources of the same fact diverge without reporting — which is the failure FR-055 exists
874
+ to remove, so "tidy duplicate" is not a fix here.
875
+
876
+ **Step 0 — the pre-exclusion, which is NOT a row in the table below.** Before consulting
877
+ any destination, ask: **is this an execution deviation** — did a command simply not do
878
+ what was already written for it? If yes, **fix it in place and register nothing.** It is
879
+ not a destination, it is the *absence* of one; giving it a row would create a section
880
+ whose consumer nobody can name, violating Principle II ("an artifact no downstream
881
+ consumer reads should not be generated"). The other three questions only apply after
882
+ this one answers *no*.
883
+
884
+ **Step 1 — the gate for tool defects.** A defect in specpro's own source
885
+ (`commands/` · `templates/` · `scripts/`) is first checked against **FR-047's shape
886
+ register**. ⚠️ **The comparison is per shape, one at a time, against that shape's own
887
+ criterion** (FR-047 / FR-049) — not a glance at the register to see which entry "looks
888
+ closest":
889
+
890
+ 1. **Read both halves.** `spec.md` → FR-047 carries the shapes and what each one *is*;
891
+ `plan.md` → Constraint 7 carries the detection table — how each is detected and what
892
+ counts as a hit. ⚠️ **The statement alone is not enough**: a shape whose detection
893
+ method you have not read cannot be ruled in or out, only guessed at.
894
+ 2. **Test the finding against each shape's criterion in turn**, and record the verdict per
895
+ shape — in or out, and why. ⚠️ **"It resembles shape N" is not a verdict.** "It
896
+ satisfies shape N's detection, and shape N's check would fire on it" is.
897
+ 3. **A finding that satisfies no shape's criterion is registered for `[specify]`** so a
898
+ **new shape** is added (FR-049). ⚠️ **It MUST NOT be absorbed into the nearest existing
899
+ shape** — from the register's side an absorption is indistinguishable from a defect that
900
+ was fixed, which is exactly how the register stops meaning anything.
901
+ 4. ⚠️ **What that `[specify]` entry MUST carry** — this is FR-049's own acceptance
902
+ (`spec.md` → US10): the candidate shape described as **a criterion a command could
903
+ evaluate** — what counts as an instance, what counts as a hit, and what a re-run would
904
+ look for. ⚠️ **A shape that cannot be turned into a criterion is not a shape, it is a
905
+ container** — and a register that admits containers *is* the container it exists to
906
+ replace.
907
+
908
+ Only once the finding is placed in an existing shape does the table below decide where it
909
+ goes.
910
+
911
+ | The finding is about… | Register in | Consumed by |
912
+ |-----------------------|-------------|-------------|
913
+ | Requirement content — missing / unclear / conflicting FR or US text, a requirement's protocol specification gaps, the spec's own coverage of a mandated section | `[specify]` | `/specpro-specify --review-issues` |
914
+ | Design, architecture, or a contract under `specs/contracts/` — design gaps, anchor/model defects, load-bearing assumptions that proved false, contract facts with no supportable source | `[plan]` | `/specpro-plan --review-issues` |
915
+ | Task descriptions, ordering, dependencies, **a missing task** (Pass E: an FR with no carrier on any route), or a defect in the product of a `tasks.md` task — **including test-infrastructure work dispatched there as `[Quality]` tasks** (e.g. the codec test-matrix / golden-fixture / test-host family, planned by `/specpro-plan` + `/specpro-tasks`) | `[tasks]` | `/specpro-tasks --review-issues` |
916
+ | A `spec.md` **Lifecycle field whose DATA is stale in this project** (Pass F) — e.g. constant across every item because it was seeded before the mechanism existed, or a `processed` marker with no work behind it. Register as a **project-level data annotation**, never as a mechanism-level prohibition | `[specify]` | `/specpro-specify --review-issues` |
917
+ | Planning errors in `specs/test-tasks.md` — coverage-matrix rows (missing / stale / verdict wrong), INF/IT/CE/AE task content, Location grounding, task↔matrix annotation mismatch; or a defect in the product of a `test-tasks.md` task | `[test-plan]` | `/specpro-test-plan` (incremental run) |
918
+ | The **constitution** itself is wrong or missing a clause — a principle that no longer matches the practice it governs, a carve-out written narrower than its intent, a governance rule with no enforcement point | `[constitution]` | `/specpro-constitution --review-issues` |
919
+
920
+ When a finding spans stages, register it **where the fix lands**. A missing verdict left by an earlier stage belongs to the stage that should have produced it, not to the stage that noticed it.
921
+
922
+ **Test-infrastructure defects route by the artifact that planned the infrastructure** ⚠️: do not send them to `[tasks]` by default. A verification harness that cannot terminate is a `[tasks]` finding when that harness is the product of a `tasks.md` task, and a `[test-plan]` finding when it is the product of a `test-tasks.md` task. Misrouting it files the finding where its planner will never read it.
923
+
924
+ **Entry shape**:
925
+
926
+ ```markdown
927
+ - [ ] ISS-NNN: <what is wrong, one line> (source: /specpro-analyze <date>, <Pass id>)
928
+ **Evidence**: <anchor — an FR / US / T identifier or a section heading — + the quoted text it points at>
929
+ **Recommendation**: <what the consuming stage should do>
930
+ ```
931
+
932
+ - The **source** line is mandatory — it is what lets a later reader tell an analyzed finding from a guessed one.
933
+ - **Evidence must be re-runnable — and durable** (`FR-022`): cite an **anchor that survives edits to the artifact** (a requirement / story / task identifier, or a section heading) **together with the quoted text** it points at. A line number MAY accompany the anchor but **MUST NOT stand alone** (⚠️ this line used to read *"a path with a line number, or a command and its observed output"*, which made the line number sufficient — `T107`): the artifacts under analysis are **continuously evolving**, so one insertion shifts every line below it, and **a stale line number does not error** — it opens on someone else's text while the reader takes it as evidence. A **command plus its observed output** stays valid: it re-derives the state rather than pointing into it.
934
+ ⚠️ **The failure this replaces is not hypothetical**: the finding that produced this rule (`T107`) cited `analyze.md:817` and `:812`; by the time it was executed those two sites had moved to `:898` and `:893` — a reader following the recorded numbers lands on unrelated text, and nothing reports it.
935
+
936
+ **Entry placement**: append the new entry to the **end of its own section**, never to the end of the file. The file's statistics block sits at the top for exactly this reason — "append to the end" then lands inside the last section. Adding or duplicating a section header instead splits the section, and the orphaned part is silently skipped by every consumer run. If the target section does not exist yet (e.g. `[test-plan]` before the first test-execution finding), create the section **at the end of the file but BEFORE the end-of-file sentinel** (the trailing `<!-- ⚠️ … -->` comment on the file's last line — never place a section after it) with its one-line scope description, following the existing sections' shape.
937
+
938
+ **Statistics**: after appending, update the `[N] → [N+1]` count and the pending-items column of the statistics table at the **top** of `implement_issues.md`; add the section's row if it is not there yet.
939
+
940
+ **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:
941
+ ```bash
942
+ grep -qE '^- \[[x ]\] ISS-<N>:' specs/implement_issues.md # correct — matches an ENTRY, not a mention
943
+ # grep -q 'ISS-<N>' … # wrong — also matches the statistics Pending-Items column, the Last Updated line, cross-references
944
+ ```
945
+ `.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.
946
+
947
+ **Verify mechanically after writing** ⚠️: run `.specpro/scripts/bash/verify-ledger.sh`. One pass checks all of the above — section membership of every entry (nothing past the sentinel), statistics-vs-actual counts per section, and the single trailing newline. It exits non-zero and names the offending entry on any violation. A pre-commit hook enforces the same check, so a violation blocks the commit rather than being discovered later.
948
+
949
+ **Never mark an entry `[x]`** ⚠️: registration is routing, resolution belongs to the owning stage. `[specify]` / `[plan]` / `[tasks]` are resolved by their `--review-issues` runs; **`[test-plan]` has no `--review-issues` flag** — it is resolved by the next incremental `/specpro-test-plan` run, which is also the only party that may check it off.
950
+
951
+ **Report**: list what was registered (IDs + target sections) in the report's Next Actions block, so the user sees the queue change rather than discovering it later.
952
+
953
+ **When nothing is found**: if a pass produced no CRITICAL/HIGH/MEDIUM finding, register nothing and say so — an empty run is a valid result, not a failure to produce entries.
954
+
955
+ ### 8. Execution Summary 🆕 (Performance tracking)
956
+
957
+ Track and report execution time breakdown:
958
+
959
+ ```markdown
960
+ ## ⏱️ Execution Summary
961
+
962
+ **Total Time**: [T_total]s
963
+
964
+ **Performance Breakdown**:
965
+ ┌──────────────────────────┬─────────┬──────────┬─────────┐
966
+ │ Phase │ Time │ % │ Status │
967
+ ├──────────────────────────┼─────────┼──────────┼─────────┤
968
+ │ Context Initialization │ [T1] │ [P1]% │ ⚡ Fast │
969
+ │ Artifact Loading │ [T2] │ [P2]% │ ⚡ Fast │
970
+ │ Lifecycle Filtering │ [T3] │ [P3]% │ ⚡ Cached│
971
+ │ Detection Passes │ [T4] │ [P4]% │ │
972
+ │ ├─ Duplication Detection │ [T4a] │ [P4a]% │ │
973
+ │ ├─ Ambiguity Detection │ [T4b] │ [P4b]% │ │
974
+ │ ├─ Test-First Check │ [T4c] │ [P4c]% │ 🆕 │
975
+ │ ├─ Test Matrix Gaps │ [T4e] │ [P4e]% │ 🆕 │
976
+ │ └─ Performance Metrics │ [T4d] │ [P4d]% │ 🆕 │
977
+ │ Severity Assignment │ [T5] │ [P5]% │ │
978
+ │ Report Generation │ [T6] │ [P6]% │ │
979
+ │ Persistence (if enabled) │ [T7] │ [P7]% │ 🆕 │
980
+ └──────────────────────────┴─────────┴──────────┴─────────┘
981
+
982
+ **Optimization Opportunities**:
983
+ - [List slowest phases and suggestions]
984
+ ```
985
+
986
+ ### 9. Result Persistence 🆕 (if --persist flag present)
987
+
988
+ **Purpose**: Save analysis results for trend tracking and specpro.status integration
989
+
990
+ **Persistence Location**: `specs/analysis/analysis-[timestamp].md`
991
+
992
+ **File Format**:
993
+ ````markdown
994
+ # Analysis Report - [FEATURE_NAME]
995
+
996
+ **Generated**: [Timestamp]
997
+ **Analysis ID**: [UUID]
998
+ **Spec Version**: [from spec.md]
999
+ **Analysis Mode**: [Full | Incremental]
1000
+
1001
+ ## Executive Summary
1002
+
1003
+ [Same as detailed report]
1004
+
1005
+ ## Detailed Findings
1006
+
1007
+ [Same as detailed report]
1008
+
1009
+ ## Metrics Snapshot
1010
+
1011
+ ```json
1012
+ {
1013
+ "timestamp": "[ISO8601]",
1014
+ "analysis_id": "[UUID]",
1015
+ "total_issues": N,
1016
+ "critical": M,
1017
+ "high": P,
1018
+ "medium": Q,
1019
+ "low": R,
1020
+ "coverage_percent": X,
1021
+ "test_first_violations": {
1022
+ "high_risk": M,
1023
+ "medium_risk": P
1024
+ },
1025
+ "test_matrix": {
1026
+ "built": true,
1027
+ "frs_tracked": N,
1028
+ "zero_coverage_frs": M,
1029
+ "single_layer_high_risk_modules": K,
1030
+ "test_tasks_completed": A,
1031
+ "test_tasks_total": B
1032
+ }
1033
+ }
1034
+ ```
1035
+
1036
+ ## Trend Analysis 🆕 (if previous analyses exist)
1037
+
1038
+ Compare with previous analysis results:
1039
+ - Track issue count trends (improving/worsening)
1040
+ - Track coverage percentage trends
1041
+ - Identify recurring issues
1042
+ - Measure quality improvement over time
1043
+
1044
+ **Example**:
1045
+ ```markdown
1046
+ ## Quality Trend
1047
+
1048
+ | Date | Critical | High | Medium | Low | Coverage % | Trend |
1049
+ |------|----------|------|--------|-----|------------|-------|
1050
+ | 2026-01-28 | 5 | 12 | 8 | 3 | 65% | - |
1051
+ | 2026-01-29 | 2 | 8 | 6 | 4 | 78% | ✅ Improving |
1052
+ | 2026-01-30 | 0 | 3 | 4 | 2 | 85% | ✅ Improving |
1053
+
1054
+ **Improvement**: -5 critical issues, +13% coverage in 2 days
1055
+ ```
1056
+ ````
1057
+
1058
+ ### 10. Provide Next Actions
1059
+
1060
+ At end of report, output a concise Next Actions block:
1061
+
1062
+ - If CRITICAL issues exist: Recommend resolving before `/specpro-implement`
1063
+ - If only LOW/MEDIUM: User may proceed, but provide improvement suggestions
1064
+ - Provide explicit command suggestions, and **name the OWNER of each artifact the finding touches** — this command does not repair (`ISS-141`). Examples: "Run `/specpro-plan --review-issues` to adjust the architecture", "Run `/specpro-tasks --review-issues` to add coverage for 'performance-metrics'", "Run `/specpro-specify --review-issues` for a requirement-level finding"
1065
+
1066
+ ### 11. Offer Remediation
1067
+
1068
+ Ask the user: "Would you like me to suggest concrete remediation edits for the top N issues?"
1069
+
1070
+ ⚠️ **Suggest, never apply.** What this step produces is a proposal for the artifact's **owning** command to carry out in its `--review-issues` run — not an edit this command makes (`ISS-141`).
1071
+
1072
+ ### 12. Integration with specpro.status 🆕
1073
+
1074
+ If PERSIST_MODE=true the saved analysis file is read back by `/specpro-status`. ⚠️ **Name only what that command actually parses** — a claim here describes a consumer, so an unbacked one reads as a working integration (`T230` / `ISS-203`). Verified against `commands/specpro.status.md` → `Step 6.7`, which reads exactly these and renders them in the dashboard:
1075
+ - Quality trend visualization — the artifact's `## Quality Trend` table, rendered verbatim
1076
+ - Test-First compliance monitoring — `"high_risk"` / `"medium_risk"`, rendered as the risk-level violation counts
1077
+ - Severity counts and coverage — `"critical"` / `"high"` / `"medium"` / `"low"` / `"coverage_percent"`
1078
+
1079
+ ⚠️ **Two entries were removed, not because they were stale but because nothing consumed them**: `constitution_violations` and `performance_metrics_missing` were written into the Metrics Snapshot but **no command read them** (not the dashboard, not the trend comparison — the trend table's columns are date / severities / coverage only). A promise with no consumer is the same defect as a mechanism with no enforcement point. **如果将来要接它们,先给它们一个真的解析点,再写回这一行** —— 不要先把承诺写回来。
1080
+
1081
+ ## Operating Principles
1082
+
1083
+ ### Context Efficiency
1084
+
1085
+ - **Minimal high-signal tokens**: Focus on actionable findings, not exhaustive documentation
1086
+ - **Progressive disclosure**: Load artifacts incrementally; don't dump all content into analysis
1087
+ - **Token-efficient output**: Limit findings table to 50 rows; summarize overflow
1088
+ - **Deterministic results**: Rerunning without changes should produce consistent IDs and counts
1089
+ - **Lifecycle-aware filtering**: Incremental mode only analyzes changed items
1090
+
1091
+ ### Analysis Guidelines
1092
+
1093
+ - **Always READ-ONLY over the analyzed artifacts** (the ledger and `specs/analysis/` are the only things this command writes)
1094
+ - **NEVER hallucinate missing sections** (if absent, report them accurately)
1095
+ - **Prioritize constitution violations** (these are always CRITICAL)
1096
+ - **Use examples over exhaustive rules** (cite specific instances, not generic patterns)
1097
+ - **Report zero issues gracefully** (emit success report with coverage statistics)
1098
+ ⚠️ "Zero" here means **no known instance among the subjects this run examined** — it MUST NOT be
1099
+ written as 「无缺陷」 (FR-050). Carry the coverage declaration: what was scanned, and what was NOT.
1100
+
1101
+
1102
+