@pavp/storywright 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,114 +1,312 @@
1
1
  ---
2
2
  name: story-refine
3
- description: Audit an existing user story for gaps and fill them in place. Surfaces missing AC, DoD, edge cases, risks; asks clarifications only for blocking unknowns. Returns dual-format refined story.
3
+ description: Audit an existing user story and fix it in place. Cohn+Gherkin canonical output. Asks clarifications ONLY in terminal. Recommends split when story has multiple outcomes.
4
4
  trigger: "/story-refine | refine this story | improve this story | refinar historia | this story is incomplete"
5
- intent: Refinement skill for stories that already exist but are incomplete or weakly specified. Composes the same component skills as story-generate but skips the drafting step.
6
- version: 1.0.0
5
+ intent: Refinement skill for stories that already exist but are incomplete or weakly specified. Default philosophy = Mike Cohn (story is a conversation starter, not a spec). Splits aggressively. Never produces mini-PRDs.
6
+ version: 2.2.0
7
7
  inputs:
8
8
  - text
9
9
  - image
10
10
  - figma-link
11
11
  outputs:
12
- - story.jira-wiki.md
13
12
  - story.standard.md
14
- - clarifications.md
13
+ - story.jira-wiki.md
14
+ - .storywright-context.json
15
15
  composes:
16
16
  - _components/clarification-questions
17
17
  - _components/acceptance-criteria
18
18
  - _components/invest-checklist
19
- - _components/definition-of-done
20
- - _components/business-rules
21
- - _components/edge-cases
22
- - _components/analytics-events
23
- - _components/risks-and-dependencies
24
19
  - _components/jira-wiki-formatter
25
20
  ---
26
21
 
27
22
  ## Purpose
28
23
 
29
- When the PM already has a story written but it's missing sections, has hand-wavy ACs, or never went through INVEST, this skill brings it up to standard without rewriting it from scratch.
24
+ Bring an existing user story up to standard *without* turning it into a feature spec. Output is conversation-ready, Cohn-format, Gherkin AC. If the story is too big, recommend split do not refine an oversized story into a longer one.
25
+
26
+ ## Hard rules (no exceptions)
27
+
28
+ 1. **Terminal-only clarifications.** Never write any sidecar question file. All gap questions go through `AskUserQuestion` (batch in groups of ≤4). If a gap is non-blocking, mark `⚠️ Assumed` inline in the story body — do not ask.
29
+
30
+ 2. **Cohn + Gherkin canonical.** One Use Case block. One AC scenario per story (one Given chain, one `When`, one `Then`). If the story naturally needs >1 `When`/`Then` → **STOP refining, recommend `/story-split`**.
31
+
32
+ 3. **No mini-PRDs.** The following sections are PROHIBITED in story output (they belong to DoD, design handoff, or sibling tickets):
33
+ - Non-Functional Requirements blocks (a11y/i18n/perf/tokens) — these live in the team's global Definition of Done
34
+ - Edge Cases enumerations — sibling stories or DoD
35
+ - Dependencies as prose — use Jira ticket links instead
36
+ - Visual specs derived from raster mockups (pixel measurements, hex inferences) inline with each claim
37
+ - Refinement logs >3 lines (>5 if verdict is SPLIT RECOMMENDED)
38
+
39
+ 4. **Output language matches the user's chat language**, not the story's. Auto-detect first (see rule 4a); only ask via `AskUserQuestion` if detection is ambiguous.
40
+
41
+ 5. **Visual inference confidence — single banner only.** Do NOT tag every visual claim. Instead, add ONE banner at the top of the Design Reference block declaring the source type. All claims under that block inherit the banner's confidence level.
42
+ - Raster source (PNG/JPG) → banner: `**Source: raster mockup → all visual specs are pixel-derived, not token-confirmed.**`
43
+ - Figma source → banner: `**Source: Figma → values can be tokenized at implementation.**`
44
+ - Design-token source → banner: `**Source: design tokens → values are authoritative.**`
45
+ - Never assert hex values, pixel sizes, or exact spacing from raster without the raster banner.
46
+
47
+ 6. **Sibling task IDs.** If story body references "next task", "future task", "another story", "siblings" — check `<output-folder>/.storywright-context.json` first (rule 9). If unresolved, ask via `AskUserQuestion`. If user has none yet, leave a `TODO: link sibling` placeholder, do not invent (unless rule F applies — see below).
48
+
49
+ 7. **Mockup chrome detection — closed list.** Chrome = exactly these elements:
50
+ - left nav rail / sidebar
51
+ - top bar (user menu, global breadcrumbs, global search)
52
+ - footer
53
+ - persistent toast/snackbar slot
54
+ - persistent modal scrim
55
+ - app-level tabs
56
+
57
+ If companion image shows any of the above and the story body does not mention them, ask via `AskUserQuestion` whether each one is in-scope, sibling-scope, or out-of-scope. Anything not on this list (cards, section headers, in-flow buttons) is NOT chrome — do not surface as a chrome question.
58
+
59
+ 8. **Anti-PRD is part of INVEST `Small`, not a separate step.** See `[[invest-checklist]]` step 7 — line count ceiling lives inside the `Small` criterion so there is one source of truth.
60
+
61
+ 9. **Cross-skill context persistence.** When the skill resolves any clarification via `AskUserQuestion`, write the **answers** to `<output-folder>/.storywright-context.json`. This is NOT a question file — it is a resolved-answers file. Read only from the exact output folder of the current invocation; never search siblings or parents. Schema:
62
+ ```json
63
+ {
64
+ "version": 1,
65
+ "decided_at": "<ISO date>",
66
+ "decided_by_skill": "story-refine",
67
+ "language": "EN | ES | ...",
68
+ "chrome_scope": "in-scope | in-scope-placeholder | sibling | out-of-scope",
69
+ "siblings": "TODO | <list of IDs> | not-applicable",
70
+ "design_source": "raster | figma | tokens",
71
+ "naming_pattern": "<see rule F>",
72
+ "extra": {}
73
+ }
74
+ ```
75
+ Future skills (`story-split`, `story-from-figma`, etc.) MUST read this file before re-asking the same questions.
76
+
77
+ 10. **Children independence — mechanical detection (A).** When the skill recommends or executes split, build an NxN dependency matrix MECHANICALLY, not by intuition:
78
+ - For each child Cj, parse its `Given:` and `and Given:` lines.
79
+ - If any `Given` text contains a surface noun owned by child Ci (e.g., Cj's Given mentions "the grid" and Ci's title/scope owns "grid") → mark `DEP(Cj → Ci)`.
80
+ - The dependency map IS the union of those text matches. Do not add deps "you sense" without a Given citation.
81
+ - Affected child's INVEST `Independent` becomes `PARTIAL · depends on <Ci>`; parent EPIC lists explicit build order derived from the matrix (topological).
82
+ - Independence-by-intuition is forbidden. If a dep is real but no Given mentions it, rewrite the child's Given to make it explicit, then re-run the match.
83
+
84
+ 11. **Per-child V audit (C).** After split, for each candidate child run a one-line V test: "If only this child ships and no sibling exists, does a real user complete a real task?". If the answer is "no, useless until <other child> ships" → mark V as `WEAK · merge-upstream-candidate` and recommend merging that child into its parent surface instead of keeping it standalone. Do not let stylistic/UI-fragment children survive the split.
85
+
86
+ 12. **Passive-goal downstream prompt (G).** If the story's `I want to` verb is passive/observational (`view, see, read, browse, look at, inspect, monitor`) and the `so that` does not name a follow-up user action — ask once via `AskUserQuestion`: "What does the user do with this data?". Use the answer to strengthen the `so that` clause. This forces explicit value. Skip the prompt if `so that` already names a downstream action (e.g., "so that I can call the customer").
87
+
88
+ ### 4a. Language auto-detect — expanded signals (E)
89
+
90
+ Run cheap detection before asking. Look at multiple signals, not just Gherkin keywords:
91
+
92
+ | Signal | Where to look | Weight |
93
+ |---|---|---|
94
+ | Gherkin keywords in M ("Given/When/Then") | AC block | high |
95
+ | Persona phrasing in M ("As a user" vs "Como un usuario") | Use Case | high |
96
+ | Column / field names in M ("Phone - primary", "Teléfono - principal") | AC bullets | medium |
97
+ | Domain verbs in M ("clicking" vs "hacer clic", "submitting" vs "enviar") | AC bullets | medium |
98
+ | Title language | header | low |
99
+
100
+ **Decision:**
101
+ - All high+medium signals agree on language M → adopt M silently. No question. Mark inline `⚠️ Assumed: output language = <M> (auto-detected from <signals>)`.
102
+ - Signals split (some EN, some ES) → ask once via `AskUserQuestion`.
103
+ - User-chat language = L, story-body signals = M, but high signals tie → prefer M (story body is contract).
104
+
105
+ Persist via rule 9.
106
+
107
+ ### Rule F. Naming pattern — ask once, persist
108
+
109
+ When the skill needs to invent a tentative ticket slug (e.g., for sibling references with no IDs yet) AND `.storywright-context.json` has no `naming_pattern` field, ask once via `AskUserQuestion`:
110
+
111
+ ```
112
+ Which naming pattern do you use for tickets?
113
+ - kebab-case feature-action → "customer-search-bar-wire"
114
+ - verb-noun → "wire-search-bar"
115
+ - domain-action → "search.customer.wire-input"
116
+ - Jira prefix + numeric → "CSB-001" (assume next available)
117
+ ```
118
+
119
+ Persist the answer in `.storywright-context.json` under `naming_pattern`. Use it for all sibling slugs in the current run AND future skills reading the same context file.
30
120
 
31
121
  ## When to use
32
122
 
33
123
  - User pastes an existing story (text) and asks to make it Jira-ready.
34
- - A story has ACs but no DoD, or vice versa.
124
+ - A story has ACs but no testable outcomes.
35
125
  - INVEST gate fails on `Testable` or `Negotiable` — fixable in place (not splittable).
36
126
 
37
- For oversized stories that fail `Independent / Estimable / Small`, hand off to `[[story-split]]` instead.
127
+ For oversized stories that fail `Independent / Estimable / Small`, OR have multiple `When`/`Then` pairs, OR have >1 distinct outcome (per the deterministic counter below) → hand off to `[[story-split]]` instead.
38
128
 
39
129
  ## Inputs & interpretation
40
130
 
41
131
  - **text** — existing story. Detect which sections are present, which are missing, which are weak.
42
- - **image (optional)** — companion screenshot/mockup the story references. Use to validate UI claims and surface missing edge cases / states.
43
- - **figma-link (optional)** — companion design. Use to enrich Technical Considerations, Edge Cases (states shown but not in story), and to detect scope mismatches.
132
+ - **image (optional)** — companion screenshot/mockup. Use to validate UI claims only. NEVER as source for pixel-precise visual specs inline with each AC claim (see rule 5).
133
+ - **figma-link (optional)** — companion design. Use to enrich AC observable outcomes (states, named components).
134
+
135
+ ### Mixed inputs source-priority
136
+
137
+ - Story text canonical for `User Story / Scope / Business value`.
138
+ - Image/Figma canonical for `component names / observable states` referenced inside AC.
139
+ - Conflicts → BLOCKING `AskUserQuestion`. Never silently rewrite the story to match the design.
140
+
141
+ ## Canonical output shape (this is the WHOLE story)
142
+
143
+ ```markdown
144
+ ### [Title]
145
+
146
+ #### Use Case
147
+ - **As a** [persona]
148
+ - **I want to** [action]
149
+ - **so that** [outcome with downstream action — see rule G]
44
150
 
45
- ### Mixed inputs
151
+ #### Preconditions (optional, only if user provided)
152
+ - ...
46
153
 
47
- When the user pastes a story plus an image / Figma link, apply the source-priority matrix from `[[story-generate]]` "Mixed inputs" section:
48
- - Story text remains canonical for `User Story / Scope / Business Goal`.
49
- - Image/Figma is canonical for `Components / States / Edge Cases / UX flow`.
50
- - Surface conflicts as BLOCKING clarifications (e.g., story says "single provider" but Figma shows multiple). Never silently rewrite the story to match the design without asking.
154
+ #### Out of Scope (optional, only if user provided)
155
+ - ...
156
+
157
+ #### Acceptance Criteria
158
+ - **Scenario:** [single-outcome scenario name]
159
+ - **Given:** [context — surface nouns here drive dep matrix per rule A]
160
+ - **and Given:** [context]
161
+ - **When:** [single trigger]
162
+ - **Then:** [single observable outcome]
163
+
164
+ #### Design Reference (optional)
165
+ **Source: <raster | figma | tokens> → <inherited-confidence banner from rule 5>**
166
+ - [link or path]
167
+ - visual notes: [...]
168
+
169
+ #### INVEST
170
+ - I/N/V/E/S/T — one line each, evidence-based.
171
+ - **Verdict:** READY | SPLIT RECOMMENDED | NEEDS REFINEMENT | NOT A STORY
172
+
173
+ #### Refinement log (≤3 lines; ≤5 if verdict=SPLIT)
174
+ - ...
175
+ ```
176
+
177
+ Nothing else. No NFR block. No Edge Cases enumeration. No Dependencies prose. No Assumptions block (assumptions get `⚠️ Assumed` inline or are resolved via `AskUserQuestion`).
51
178
 
52
179
  ## Application (step-by-step)
53
180
 
54
- 0. **Detect companion sources** (image, figma-link). If present, run conflict detection against the story text BEFORE filling sections. Add detected conflicts to the gap-check output.
55
- 1. **Parse the existing story.** Map content into the 15-section taxonomy. Note: present / missing / weak.
56
- 2. **Gap-check the weak sections** via `[[clarification-questions]]`. If gaps are inferrable, mark `⚠️ Assumed` and proceed. Only ask BLOCKING questions.
57
- 3. **Detect language** of the existing story; preserve it in the output.
58
- 4. **Fill missing/weak sections** in dependency order:
59
- - Reglas de negocio → `[[business-rules]]`
60
- - Consideraciones técnicas inline
61
- - Edge cases → `[[edge-cases]]`
62
- - Criterios de aceptación → `[[acceptance-criteria]]`
63
- - Analytics → `[[analytics-events]]`
64
- - Riesgos + dependencias → `[[risks-and-dependencies]]`
65
- - DoD → `[[definition-of-done]]`
66
- 5. **Preserve original wording** where it was already good. Mark changed sections with a comment trail at the end of the story:
67
- ```
68
- ---
69
- Refinement log:
70
- - Added Edge Cases (8 cases)
71
- - Strengthened AC-2 (was untestable: "should work properly")
72
- - Added analytics block
73
- ```
74
- 6. **Run INVEST** via `[[invest-checklist]]`.
75
- - `READY` render outputs.
76
- - `NEEDS REFINEMENT` iterate on the failing dimension.
77
- - `SPLIT RECOMMENDED` STOP. Tell the user the story should go through `[[story-split]]` instead.
78
- 7. **Render** both outputs via `[[jira-wiki-formatter]]`.
79
- 8. **Emit `clarifications.md`** if assumptions remain unresolved.
181
+ 0. **Detect companion sources** (image, figma-link). Run conflict detection against story text. Run chrome-detection using the closed list in rule 7. Surface conflicts as BLOCKING `AskUserQuestion` calls.
182
+
183
+ 1. **Parse story** into the canonical sections above. Note: present / missing / weak.
184
+
185
+ 2. **Read prior context.** If `<output-folder>/.storywright-context.json` exists (exact folder only — no sibling fallback), load it. Apply resolved answers; skip the corresponding questions.
186
+
187
+ 3. **Language resolution (rule 4 + 4a).** Auto-detect using the expanded signal table. Ask only if signals split. Persist via rule 9.
188
+
189
+ 4. **Passive-goal check (rule G).** If `I want to` verb is observational AND `so that` lacks downstream action ask once. Persist resolution into the strengthened `so that` clause.
190
+
191
+ 5. **Gap-check.** For each weak/missing section:
192
+ - **Blocking** (changes scope, AC outcome, or persona) → `AskUserQuestion` immediately (batched ≤4).
193
+ - **Non-blocking** (additive detail) fill inline marked `⚠️ Assumed: <text>`. Do not ask.
194
+
195
+ 6. **Sibling reference check (rule 6).** If found and unlinked → ask via `AskUserQuestion` once. If user opts for tentative slugs, apply rule F (naming pattern). Persist via rule 9.
196
+
197
+ 7. **Deterministic pre-split test.** Apply this counter mechanically — do not eyeball:
198
+
199
+ **Count = sum of all hits below:**
200
+ | Signal | Hit value |
201
+ |---|---|
202
+ | AC bullet starting with an action verb at the user level ("clicking", "submitting", "entering", "navigating") | +1 each |
203
+ | Distinct `When [event]` phrasing already implied in the story | +1 each |
204
+ | Distinct named UI surface mentioned at the AC level see (D) below for what counts | +1 each |
205
+
206
+ **(D) Surface vs styling rule (deterministic).** A "named UI surface" counts as +1 ONLY if it has its own user goal — meaning there is a verb in the story body where the user *does something with that surface* (clicks it, navigates with it, reads it, configures it). If a noun is mentioned only in a styling context (color, background, padding, alignment) or as a sub-component of a parent surface (column inside a grid, label inside a button) → it is NOT a surface. It is styling. Count = 0.
207
+
208
+ Examples:
209
+ - "header row visually distinct (purple background)" — styling of grid → 0
210
+ - "pagination control with page numbers and arrows" — surface with user goal (navigating) → +1
211
+ - "5 columns: Code, Customer name, Phone, Email, Address" — columns are sub-components of grid → 0 (grid still counts once)
212
+ - "results counter next to search button" — surface with user goal (reading count) → +1
213
+
214
+ **Do NOT count:**
215
+ - sub-bullets describing the same flow (column names inside one grid = the grid itself, not separate outcomes)
216
+ - styling of an existing surface (header purple = part of grid, not a new outcome)
217
+ - preconditions or "rendered" statements (passive layout assertions are not Whens)
218
+
219
+ **Decision:**
220
+ - Count ≤1 → continue to step 8.
221
+ - Count ≥2 → **STOP. Recommend `/story-split` via terminal message.** Output: list of candidate children + per-pair dependency note (rule 10) + V audit per child (rule 11).
222
+
223
+ 8. **Fill the weak sections** using `[[acceptance-criteria]]` (single Gherkin block) and `[[invest-checklist]]`. Preserve original wording where it was already good.
224
+
225
+ 9. **Run INVEST** via `[[invest-checklist]]` (which embeds the anti-PRD line-count check inside `Small` — rule 8).
226
+ - `READY` → render.
227
+ - `SPLIT RECOMMENDED` → STOP, recommend split (and run rule 10 children-independence matrix + rule 11 V audit per child).
228
+ - `NEEDS REFINEMENT` → iterate failing dimension, max 1 cycle, then STOP.
229
+ - `NOT A STORY` → tell user it's a tech task and stop.
230
+
231
+ 10. **Render** both outputs via `[[jira-wiki-formatter]]`. Files: `story.standard.md` + `story.jira-wiki.md`. Plus `.storywright-context.json`. No other files.
232
+
233
+ 11. **Refinement log** ≤3 bullets (≤5 if SPLIT) appended at story end.
80
234
 
81
235
  ## Examples
82
236
 
83
- ### Good
237
+ ### Good — READY
238
+ Input: story with title + Use Case + 2 vague ACs.
239
+ Output: canonical block, ≤30 lines, AC tightened to single Given/When/Then, INVEST verdict READY, ≤3-line refinement log, `.storywright-context.json` written.
84
240
 
85
- Input: a story with title + User Story + 2 vague ACs ("It should be fast", "User can log in").
241
+ ### Good SPLIT (Spanish)
242
+ Input: historia con 7 bullets de AC (grilla + contador + paginación + link).
243
+ Output: NO refined story. Mensaje terminal:
244
+ ```
245
+ SPLIT RECOMMENDED. Conteo determinístico = 4 (grilla, contador, paginación, link).
246
+ Children candidatos:
247
+ 1. Page shell + chrome (si in-scope)
248
+ 2. Grid 5 columnas + header style
249
+ 3. Contador de resultados
250
+ 4. Control de paginación
251
+ 5. Link affordance en customer name
252
+ Matriz independencia (parse mecánico de Given):
253
+ - C4.Given menciona "the grid" → DEP(C4 → C2) → PARTIAL
254
+ - C5.Given menciona "the grid" → DEP(C5 → C2) → PARTIAL
255
+ - Orden build: C1 → C2 → {C3, C4, C5}
256
+ V audit per child:
257
+ - C1: PASS (chrome funcional = workspace context)
258
+ - C2: PASS (read records)
259
+ - C3: WEAK · merge-upstream-candidate — counter sin grid no entrega valor
260
+ - C4: PASS (navigate pages)
261
+ - C5: PASS (link affordance)
262
+ Corré /story-split para expandir; considera mergear C3 en C2.
263
+ ```
86
264
 
87
- Output:
88
- - Original title/user story preserved.
89
- - AC-1 rewritten to Given/When/Then with observable outcomes.
90
- - AC-2 split into AC-2 (happy path) and AC-3 (failure path).
91
- - Added Edge Cases section (5 cases).
92
- - Added DoD section.
93
- - Refinement log appended.
265
+ ### Good — passive-goal prompt fires
266
+ Input: "As a user, I want to view list of customers, so that I quickly find details."
267
+ Skill detects passive verb `view` + thin `so that`.
268
+ Asks: "What does the user do with the customer they find?"
269
+ User: "Call them to schedule a service."
270
+ Refined `so that`: "so that I can quickly find a customer and call them to schedule a service."
94
271
 
95
272
  ### Bad
273
+ Adding NFR / a11y / i18n / Dependencies sections "to be thorough". Violates rule 3.
96
274
 
97
- Rewriting the whole story when only 2 sections were weak. Preserve good content.
275
+ ### Bad
276
+ Writing any sidecar question file instead of asking via `AskUserQuestion`. Violates rule 1.
277
+
278
+ ### Bad
279
+ Tagging every visual claim with `[mockup-pixel-derived]` instead of using the single banner. Violates rule 5.
280
+
281
+ ### Bad
282
+ Claiming 5 children all `Independent` after split without running the mechanical matrix from rule 10.
283
+
284
+ ### Bad
285
+ Counting "header row purple" as +1 in the pre-split test. It is styling of the grid (rule D), not a separate surface. Should be 0.
98
286
 
99
287
  ## Common Pitfalls
100
288
 
101
289
  - Treating refine like generate. If the PM already wrote the user goal, don't restate it.
102
- - Renumbering ACs the team may already reference externally. Append new ACs at the end.
103
- - Skipping the refinement log. Reviewers need to see what changed.
290
+ - Renumbering ACs append new content, don't shuffle.
291
+ - Skipping the deterministic pre-split test (step 7). Refining oversized stories produces oversized refined stories.
292
+ - Eyeballing outcome counts or dep matrix instead of running the mechanical rules (D, A).
293
+ - Re-asking questions already answered in `.storywright-context.json`.
294
+ - Letting weak-V children survive the split (rule 11).
295
+ - Skipping the downstream-action prompt for passive goals (rule G).
104
296
 
105
297
  ## References
106
298
 
107
299
  - [[story-generate]]
108
300
  - [[story-split]]
109
301
  - [[invest-checklist]]
302
+ - [[acceptance-criteria]]
110
303
 
111
304
  <claude-specific>
112
305
  - Diff the original sections against the refined ones in your reasoning; only emit changes that materially improve the story.
113
- - Cache the 15-section taxonomy.
306
+ - Never call Write for any question/clarification sidecar file. Use `AskUserQuestion`.
307
+ - Treat step 7 (deterministic pre-split test) as a hard gate; do not skip even when the user explicitly asks to refine.
308
+ - Read `.storywright-context.json` ONLY from the exact target output folder. Do not search siblings or parents.
309
+ - After split, build the dependency matrix from Given-text parsing (rule 10), not intuition.
310
+ - After split, run V audit per child (rule 11) and flag merge-upstream-candidates loudly.
311
+ - For passive `I want to` verbs, fire rule G prompt before INVEST.
114
312
  </claude-specific>