storymapper 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/ARCHITECTURE.md +334 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +6 -0
  4. package/README.md +239 -0
  5. package/frontend/css/storymap.css +4637 -0
  6. package/frontend/js/adapters.js +423 -0
  7. package/frontend/js/card-animate.js +384 -0
  8. package/frontend/js/core/graph.js +825 -0
  9. package/frontend/js/core.js +3908 -0
  10. package/frontend/js/dialog-ticket-import.js +506 -0
  11. package/frontend/js/dnd.js +322 -0
  12. package/frontend/js/filter.js +215 -0
  13. package/frontend/js/main.js +2499 -0
  14. package/frontend/js/project-io.js +109 -0
  15. package/frontend/js/query-autocomplete.js +196 -0
  16. package/frontend/js/query-engine.js +339 -0
  17. package/frontend/js/query.js +280 -0
  18. package/frontend/js/renderer-card.js +639 -0
  19. package/frontend/js/renderer-dependencies.js +974 -0
  20. package/frontend/js/renderer-kanban.js +505 -0
  21. package/frontend/js/renderer-storymap.js +2530 -0
  22. package/frontend/js/renderer-ticket-editor.js +455 -0
  23. package/frontend/js/renderer-ticket-modal.js +758 -0
  24. package/frontend/js/save-pipeline.js +170 -0
  25. package/frontend/js/smartbar-autocomplete.js +162 -0
  26. package/frontend/js/store.js +197 -0
  27. package/frontend/js/ticket-editor-boot.js +24 -0
  28. package/frontend/js/ticket-form.js +2095 -0
  29. package/frontend/js/ticket-import.js +477 -0
  30. package/frontend/js/ui-shell.js +441 -0
  31. package/frontend/js/view-process-steps.js +233 -0
  32. package/frontend/js/view-requirements.js +361 -0
  33. package/frontend/js/view-settings.js +1864 -0
  34. package/frontend/js/view-table.js +659 -0
  35. package/frontend/js/wheel-pan.js +65 -0
  36. package/frontend/storymap.html +87 -0
  37. package/frontend/ticket-editor.html +29 -0
  38. package/package.json +76 -0
  39. package/server/bus.js +16 -0
  40. package/server/core/graph.js +10 -0
  41. package/server/core.js +10 -0
  42. package/server/identity.js +134 -0
  43. package/server/index.js +283 -0
  44. package/server/ingest.js +212 -0
  45. package/server/mcp.js +2510 -0
  46. package/server/server.js +1599 -0
  47. package/server/slice.js +103 -0
  48. package/server/storage.js +571 -0
  49. package/server/validation.js +225 -0
  50. package/shared/core/graph.js +825 -0
  51. package/shared/core.js +3908 -0
  52. package/shared/project-io.js +109 -0
  53. package/shared/query-autocomplete.js +196 -0
  54. package/shared/query-engine.js +339 -0
  55. package/shared/query.js +280 -0
  56. package/shared/ticket-import.js +477 -0
  57. package/skill/SKILL.md +458 -0
  58. package/skill/reference/anatomy.md +196 -0
  59. package/skill/reference/spec-evolution.md +52 -0
  60. package/skill/reference/tools.md +156 -0
  61. package/skill/reference/workflows.md +203 -0
package/skill/SKILL.md ADDED
@@ -0,0 +1,458 @@
1
+ ---
2
+ name: storymap
3
+ description: Plan, organize, and track development work via the Story Mapper MCP server. Trigger when the user wants to plan a feature, shape a backlog, run a sprint, capture work as epics/stories/bugs, track a kanban board, define or evaluate Definition-of-Ready / Definition-of-Done, configure workflows or board columns, link tickets into dependencies, review revisions, or move tickets through statuses. Also trigger on "story map", "user story map", "kanban", "backlog", "epic", "release planning", "process step", "DoR", "DoD", "sprint planning", "ticket", "split into stories", "dependency", "blocks", "what's in progress", "show the backlog". Bidirectional: every MCP write appears live in the user's browser with highlight + movement animation; the user's manual UI edits flow back via list_/get_ reads. Use the Story Mapper as a shared thinking surface, not a write-only database.
4
+ ---
5
+
6
+ # Story Mapper skill
7
+
8
+ An **agent-first** planning surface. I am the primary acting instance: I plan
9
+ the work, write the tickets, decompose epics into stories, link dependencies,
10
+ move tickets through the workflow, and do the coding the board tracks. The
11
+ human directs and reviews — they are not a co-developer sharing the keyboard.
12
+
13
+ The Story Mapper is two things at once:
14
+
15
+ 1. **My working surface** — where I think in structure (epics, stories, links,
16
+ releases) instead of prose.
17
+ 2. **My channel to the human** — the MCP server runs alongside their browser;
18
+ every tool call I make appears live with a highlight pulse + movement
19
+ animation, and every manual edit they make flows back to me the next time I
20
+ read. It is a living, navigable plan beyond a static plan file:
21
+ epics/stories/typed-links/revisions evolve in front of the human as I work.
22
+
23
+ So: speak as the acting instance ("I created v1.0 and three stories under
24
+ Build", "the flow here is…"), surface what I'm doing and what's next, and offer
25
+ planning options rather than waiting to be told each step. It's a collaborative
26
+ whiteboard, not a write-only API — and the board, not my assumptions, is the
27
+ contract for what happens next (§4).
28
+
29
+ **This file is the always-loaded core.** Deep detail lives in `reference/`,
30
+ loaded on demand:
31
+
32
+ - `reference/anatomy.md` — the full concept model (project, release, process
33
+ step, ticket types, status, workflow + rule engine, DoR/DoD, entityTypeConfig,
34
+ board, typed links). The §2 summary below is the index.
35
+ - `reference/tools.md` — the full tool catalogue (when-to-use tables + response
36
+ shapes). The §5 index below names every tool.
37
+ - `reference/workflows.md` — step-by-step playbooks (greenfield, sprint, bundle,
38
+ plan-from-dependencies, test loop, reorganise, look back).
39
+ - `reference/spec-evolution.md` — the governance model (spec changes via
40
+ `modifies`, test-definition lifecycle, what stops `complete_ticket`).
41
+
42
+ Read the relevant reference file when a task goes past the core.
43
+
44
+ ---
45
+
46
+ ## 1. Paradigm
47
+
48
+ Three complementary lenses on the SAME body of tickets:
49
+
50
+ ### User Story Map (planning view)
51
+ Read top-to-bottom and left-to-right.
52
+
53
+ - **Horizontal axis = Process Steps** — phases of the **user's journey**
54
+ through the product, e.g. *Sign up → Onboard → Activate → First win*, or for a
55
+ marketplace *Discover → Compare → Buy → Receive → Review*. Process Steps
56
+ describe **what kind of value the user encounters** at that point in their
57
+ journey.
58
+
59
+ Process Steps are NOT statuses (todo/doing/done), NOT team workflow stages
60
+ (Design/Build/Test/Validate), and NOT technical layers (Frontend/Backend/
61
+ Infra). If a step name reads like "what the team is doing" rather than "what
62
+ the user is doing", rename it. The Kanban view is where status-driven lanes
63
+ live; the Story Map's horizontal axis is the customer's path through the
64
+ product.
65
+ - **Vertical axis = Releases** — slices of scope. Each release row spans every
66
+ process step and contains the work scheduled for that release.
67
+ - **Cells** = a (Release × Process Step) intersection. Cells hold **Epics**
68
+ (large groups of work) and the cell's epics hold **Stories** (sprint-sized
69
+ work items). A cell can also hold loose stories without an epic. Epic cards
70
+ and release rows are collapsible to tame large maps.
71
+ - **Backlog** sits below the grid: anything not yet placed in a release row or
72
+ process step. Tickets start here.
73
+
74
+ Use the Story Map to **plan features that deliver user value** — to structure
75
+ scope across releases and reorganise as priorities change. The Story Map does
76
+ NOT model engineering phases (those belong in statuses) and does NOT track
77
+ day-to-day execution (the Kanban does).
78
+
79
+ ### Kanban Board (execution view)
80
+ Read left-to-right. Lanes = configured **Board Columns** (one column may group
81
+ several statuses). Cards in each lane sorted by `sortOrder`. Epics are NOT shown
82
+ — they're containers, not work items.
83
+
84
+ Use the Kanban to drive day-to-day execution and to see at a glance what is
85
+ blocked vs. progressing.
86
+
87
+ Both views read the SAME underlying tickets. A story you reorder inside an epic
88
+ on the story-map ALSO changes its rank inside its kanban lane, because
89
+ `sortOrder` is shared. That coupling is intentional.
90
+
91
+ ### Dependency view (impact-analysis lens)
92
+ A read-only layered DAG of all tickets connected by **typed links**. Nodes are
93
+ coloured by status-category; edges by link semantic; hovering a node highlights
94
+ its predecessors + successors, with critical-path highlighting. Use it to see
95
+ sequencing, what's ready to pick, and the blast-radius of a change *before*
96
+ reorganising. Links are authored via the `link_create` tools or the ticket
97
+ detail modal — you inspect here, you don't drag.
98
+
99
+ ---
100
+
101
+ ## 2. Anatomy (index — full model in `reference/anatomy.md`)
102
+
103
+ - **Project** → **Releases** (rows, `status` planning/active/completed/cancelled)
104
+ × **Process Steps** (backbone columns, user-value labels) form the grid;
105
+ **Cells** hold **Epics** which hold **Stories**.
106
+ - **Ticket types** (7 default, `ticketTypes` configurable): `epic` (container),
107
+ `user-story`, `bug`, `technical-task-backend`/`-ui`, `test-definition`
108
+ (reusable spec, no outcome), `test-execution` (one run, carries the result).
109
+ - **Tickets start in `backlog`** — every move is an explicit transition.
110
+ - **Epic membership is a `contains` link**, not a field. `position.epicId` is
111
+ accepted as input but **reads back null** — find the epic via
112
+ `list_links_for_ticket(story, backward)` or `list_tickets(epicId=…)`. A story
113
+ inherits its epic's release + processStep.
114
+ - **Status** `{id, name, category}`, category ∈ `todo|doing|blocked|done`.
115
+ `test-execution` auto-couples status to outcome (`in-progress ↔ done`).
116
+ - **Workflow + gates**: named transitions with `requireGate: DoR|DoD|null`,
117
+ per-type overrides, a declarative rule catalog. **Lockstep invariant:** if a
118
+ type hides a field via `entityTypeConfig` (`showDefinitionOfReady/Done`,
119
+ `showTestOutcome`), the matching gate goes **N/A** for that type. Skip-moves
120
+ check only the matched transition's gate; reverse moves are ungated.
121
+ - **DoR/DoD**: project templates, frozen onto each ticket at create; required
122
+ items must be checked to pass the gate (`kind, missing[]`).
123
+ - **Typed links** (`project.linkTypes`): `predecessor-of`/`blocks` (cycle-checked
124
+ dependencies), `follows-on`, `contains`, `relates-to`, `executes`/`tests`,
125
+ `modifies`. Prefer the specific type over `relates-to`.
126
+
127
+ ---
128
+
129
+ ## 3. Bidirectional collaboration
130
+
131
+ The user has the browser open while I work. Treat the Story Mapper as a shared
132
+ thinking surface.
133
+
134
+ **I write → user sees instantly:**
135
+ - Every MCP write triggers a WebSocket push to the browser.
136
+ - New tickets pulse green; moved tickets (lane change OR field edit OR reorder)
137
+ FLIP-animate to their new position AND pulse.
138
+ - The user follows along visually, no refresh needed.
139
+
140
+ **User writes → I see on next read:**
141
+ - Manual UI edits persist immediately via REST → SQLite.
142
+ - Read with `list_tickets` / `ticket_get` / `project_get` to pick up whatever
143
+ the user changed since my last write.
144
+ - There is no server→agent push — I pull when I need current state. (A UI drag
145
+ can move a ticket out of an epic's cell and drop its `contains` link; re-read
146
+ before assuming structure is intact.)
147
+
148
+ **Direct the user's attention** with `request_switch_project(workspace, reason,
149
+ wait_seconds)`: the browser shows a confirm dialog with my `reason`; the tool
150
+ blocks until Accept/Cancel (or timeout; default 30 s, max 120) and returns
151
+ `{requested, reason, requestId, response:{accepted}, timedOut?}`. Use after
152
+ creating/preparing a project so the user lands in the right place — not for
153
+ every navigation.
154
+
155
+ **Surface what I've done** in the conversational reply. Don't make the user
156
+ mentally diff the snapshot — say *"I created v1.0, three process steps, an epic
157
+ 'Onboarding revamp' with three stories under Build, and linked the DB story as a
158
+ predecessor of the UI story"* and let the animations reinforce it.
159
+
160
+ ---
161
+
162
+ ## 4. Working from the map: tickets-first + priority discipline
163
+
164
+ The Story Mapper is not a passive log of work — it is **the contract that
165
+ governs what I do next**. These rules together; not optional. Violating them
166
+ quickly desynchronises my work from what the user expects.
167
+
168
+ ### Tickets-first
169
+ Every substantial activity in a Story-Mapper-backed project happens **inside a
170
+ ticket**. If there isn't a ticket for what I'm about to do, I create one and
171
+ pause for the user to acknowledge it — I do NOT free-form through the work and
172
+ back-fill the ticket afterwards. The user watches the Kanban to see what I'm
173
+ touching; editing files without a ticket in `in-progress` makes that invisible.
174
+
175
+ When I finish one ticket, I do NOT silently roll into the next. Stop. Propose.
176
+ Ask. See the priority rule.
177
+
178
+ **Walk the workflow as I build, not after.** A ticket's status tracks reality:
179
+ move it `backlog → ready` (DoR met) when I start, `→ in-progress` while editing
180
+ files, `→ review` when it's implemented and tested, `→ done` only when the DoD
181
+ gate is genuinely met. Don't build first and back-fill the ticket afterwards —
182
+ that drift once even collided a commit tag with an auto-assigned ticket key.
183
+
184
+ **Honest status.** Built-but-unmerged / not-yet-independently-reviewed work
185
+ belongs in `review`, not `done`. Check DoD items only when they are actually
186
+ true (AC met, automated test green); `done` requires every required DoD item —
187
+ including independent review — so a parallel reviewer (a separate agent or
188
+ session) is part of closing, not a rubber stamp.
189
+
190
+ **Epic status is DERIVED — never walk an epic.** An epic has no manual status:
191
+ it rolls up from its contained stories (empty → backlog; any story in progress →
192
+ in-progress; every story done → done). Every status path rejects an epic with
193
+ `kind=EPIC_STATUS_DERIVED` (`change_ticket_status`, `mark_ready`,
194
+ `complete_ticket`, `bulk_change_status`, and a `status` in `ticket_update.patch`).
195
+ To advance or complete an epic, move its **stories** — the epic follows. Epics
196
+ also carry no DoR/DoD (the gates are N/A). A release shows real progress as
197
+ "X/Y done" over its non-epic work items, so a release whose stories are all done
198
+ closes cleanly even though the epic was never manually touched.
199
+
200
+ ### Structure: name releases by content, keep process steps atomic
201
+ When I introduce roadmap structure, I mirror how the user thinks about it:
202
+
203
+ - **Releases are named by content, never by time.** No "Now" / "Next" /
204
+ "Future" — the name carries the substantive activity (e.g. "Durchgängige
205
+ Traceability"). An active slice with no fitting open release needs a *new*
206
+ one; never dump current work into a `completed` release.
207
+ - **Process Steps are atomic — one activity per step.** Don't fuse distinct
208
+ activities (Specify ≠ Trace ≠ Agent Planning — the last is its own step
209
+ because another actor may intervene and communication is part of it).
210
+ Decompose the journey into fine-grained steps first, then place epics.
211
+ - **Content coherence.** Don't fold unrelated work into a thematically-named
212
+ release just to avoid creating a second one.
213
+
214
+ ### Map-Check before every action
215
+ Before any substantial tool action (writing code, creating tickets, picking the
216
+ next thing), refresh the view of the map — the user may have moved tickets,
217
+ re-prioritised the backlog, renamed a Process Step, or added tickets via the UI
218
+ since my last read. Minimum read set:
219
+
220
+ - `list_tickets status="backlog"` — the priority ordering of queueable work.
221
+ - `list_process_steps` / `list_releases` — only if I might affect structure.
222
+ - `list_tickets status="in-progress"` — to confirm what's already being touched.
223
+
224
+ Map-Check is a cheap read (`compact: true` makes it cheaper). Acting on a stale
225
+ view is expensive — undoing structural changes is painful.
226
+
227
+ ### Priority comes from the map, not from my assumptions
228
+ Ticket priority is **`sortOrder` within the backlog lane** (Kanban view), or
229
+ **position within an epic** (Story Map view). Higher up = higher priority. The
230
+ user maintains this order; I read from it. To pick the next ticket:
231
+
232
+ 1. `list_tickets status="backlog"`, sort by `sortOrder` (or `next_actionable`
233
+ for the DoR-ready + unblocked subset).
234
+ 2. The top entry is the next candidate — **unless** the user signalled otherwise
235
+ ("let's do SM-X next" overrides map order).
236
+ 3. **Propose explicitly**: "Next per the map is SM-X — *Title*. OK?"
237
+ 4. Wait for confirmation. Do NOT auto-advance.
238
+
239
+ Never narrate "next I'll take X" without giving the user a chance to redirect.
240
+ The user owns the queue. (Mirror my internal task tracker — TaskCreate/Update —
241
+ to the Story-Mapper status; they are two views of the same work.)
242
+
243
+ ---
244
+
245
+ ## 5. Tool index (full when-to-use + response shapes in `reference/tools.md`)
246
+
247
+ **Compact by default (SM-123).** Ticket-returning mutators (`ticket_create`,
248
+ `ticket_update`, `change_ticket_status`, `mark_ready`, `complete_ticket`) and
249
+ `set_checklist_item` return a compact `{revision, savedAt, ticket|item:…}`; pass
250
+ **`verbose: true`** for the full object. `ticket_get` is full by default
251
+ (`compact: true` / `fields:[…]` to slim); `list_tickets` takes `compact: true`.
252
+ Act on the compact response; only go verbose when you need a field it omits.
253
+
254
+ - **Discovery** (cheap reads): `list_projects`, `project_get` (big — sparingly),
255
+ `list_tickets` (filters + `compact`), `list_releases`, `list_process_steps`,
256
+ `get_config` (`section: definitions|workflow|kanban_columns|governance|link_types`),
257
+ `resolve_definitions_for_ticket`, `list_links_for_ticket`, `next_actionable`
258
+ (the DoR-ready + unblocked do-next queue), `query_tickets` (JQL-style search;
259
+ `release`/`processStep`/`epic` match by **name OR id**, and an unknown ref
260
+ value errors loudly instead of returning a silent empty set — SM-260).
261
+ - **Setup**: `project_create`, `project_update`, `request_switch_project`,
262
+ `release_create`, `process_step_create`, `set_config` (full-replace a section).
263
+ - **Authoring**: `ticket_create`, `ticket_update`, `ticket_delete`. Acceptance
264
+ criteria are a **first-class field** — `acceptanceCriteria:[{text:…}]`, never
265
+ prose bullets in the description (AC in prose are invisible to the modal +
266
+ DoR/DoD and make `dor-acceptance` vacuously pass). **`ticket_create` accepts
267
+ `acceptanceCriteria` at creation** (SM-260) — set them up front, no
268
+ create-then-update dance. **`ticket_update` position is a partial merge**:
269
+ patch just `{releaseId}` to change the release and keep processStep + sortOrder
270
+ (omitted keys are preserved; an explicit `null` clears a field).
271
+ - **Typed links**: `link_create` (use the specific type; cycle-checked),
272
+ `link_delete`, `list_links_for_ticket`.
273
+ - **Movement**: `reorder` (`entity: tickets|releases|process_steps`; for tickets,
274
+ `orderedIds[]` + optional `scope:{releaseId,processStepId,epicId}` — `scope`
275
+ moves into a container, `scope.epicId` creates the `contains` link). Never set
276
+ `sortOrder` via `ticket_update`.
277
+ - **Bulk** (best-effort; `opts.atomic` to roll back): `bulk_change_status`,
278
+ `bulk_ticket_update`, `bulk_link_create`.
279
+ - **Datenaustausch** (SM-290/291): `import_tickets` (CSV — the export format —
280
+ or `rows:[{…}]`; mode `create-only` (default) vs `upsert` patches existing
281
+ keys with only the changed fields). Replaces N× `ticket_create` for mass
282
+ creates. Foreign CSVs (Jira, Excel): common headers auto-map (Summary→title,
283
+ Issue key→key, Issue type→type, Fix version→release); anything else via
284
+ `headerMapping: {"csv header": "field" | null}` (SM-296). Foreign VALUES
285
+ (statuses/types like `IN TESTING`, `Story`): common ones auto-map
286
+ (Open/To Do→backlog, Closed/Resolved→done, In Review→review,
287
+ Story→user-story — only if the target exists); the rest via
288
+ `valueMapping: {status: {"src": "target" | null}, type: {…}, release: {…},
289
+ processStep: {…}}` (SM-297). The dryRun plan lists `unknownValues` —
290
+ ALWAYS dryRun first, map what it lists, then apply. **ALWAYS `dryRun: true` first** and show the human the plan
291
+ (`{creates, updates, errors}` with line numbers) before applying — apply
292
+ writes everything in ONE revision, error rows are never written. Import is a
293
+ migration surface: statuses apply **without** DoR/DoD gates. `export_project`
294
+ returns the re-importable `storymap-project` envelope (same format as the
295
+ browser's Export… → Projekt (JSON)) — use it when the human wants a file/
296
+ backup/transform artifact; for plain reads stick to `project_get`.
297
+ - **Transitions**: `change_ticket_status`, `mark_ready` (→ ready, loud DoR),
298
+ `complete_ticket` (→ done — ALWAYS use this so DoD + governance gates fire;
299
+ pass `checkDoD:true` to tick every required DoD item in the same call instead
300
+ of N× `set_checklist_item` — SM-260),
301
+ `cancel_ticket` (→ cancelled, gate-free — see below),
302
+ `set_checklist_item` (`gate: dor|dod`, inline-persisted).
303
+ - **Cancel vs Delete** (`cancel_ticket`): cancel records a deliberate
304
+ non-implementation (scope reduction) — the ticket stays VISIBLE with its
305
+ history + links, just marked cancelled (a 5th terminal status category).
306
+ `ticket_delete` is for MISTAKES only (soft-delete, hidden). Cancel is
307
+ gate-free from any status; reopen by moving to an earlier status (ungated).
308
+ Cancelling an EPIC cascades: every open contained story is cancelled in one
309
+ revision and the epic rolls up to cancelled (or done, if some stories had
310
+ already shipped — the work that shipped dominates). Cancelled tickets drop
311
+ out of release progress (X/Y) and never block completing a release. Spec
312
+ types (requirement/spec-module) have their own lifecycle and reject cancel.
313
+ - **Test types**: **`derive_test_definition`** (AC → one-step-per-AC draft plan
314
+ linked back; the fast path, SM-301), `ticket_create type=test-definition`
315
+ (+ `link_create … tests`) for hand-built plans,
316
+ `test_def_prereq_add`/`_update`/`_remove`/`_check`/`_uncheck`,
317
+ `test_def_step_add`/`_update`/`_remove`/`_reorder`, `publish_test_definition`,
318
+ `reopen_test_definition`, `update_test_definition_metadata`, `test_exec_start`,
319
+ `test_exec_record`, `test_exec_set_outcome`, `test_exec_history`.
320
+ - **Reflection**: `list_revisions`, `get_revision`, `restore_revision`
321
+ (**confirm with the user first**).
322
+
323
+ ---
324
+
325
+ ## 6. End-to-end workflows → `reference/workflows.md`
326
+
327
+ Step-by-step playbooks for: plan a new initiative (greenfield), **decompose a
328
+ source PRD into a traceable requirements layer (direction A — two-stage slicing:
329
+ the server coarse-slices at headings, then YOU content-analyse each slice into
330
+ 1..n atomic requirements)**, execute a sprint, bundle related stories
331
+ (auto-complete pure-data, pause for UI smoke), plan from dependencies (sequence +
332
+ impact + traceability), validate a feature with the test loop, reorganise, and
333
+ look back. Read it when running one of these.
334
+
335
+ ---
336
+
337
+ ## 7. Spec evolution & test definitions → `reference/spec-evolution.md`
338
+
339
+ The governance model (SM-92/SM-93): HARD (tool-blocked) / SOFT (warning) /
340
+ SKILL-only layers; the test-definition lifecycle (`draft → publish → run`); and
341
+ the rule that spec changes after `ready+` go through a NEW `modifies`-ticket, not
342
+ an in-place edit. Read it before evolving a frozen spec or debugging a gate.
343
+
344
+ **Test-definitions are MANDATORY for user-story + bug (SM-299, hard gate).**
345
+ `complete_ticket` on a `user-story` or `bug` is **blocked with
346
+ `MISSING_TEST_DEFINITION` (422)** until a **published** test-definition is
347
+ linked to it via a `tests`-link. Structural, not advisory — you cannot mark
348
+ such a ticket done without an explicit test plan in the system. The flow:
349
+
350
+ **The fast path — `derive_test_definition` (SM-301):** the acceptance criteria
351
+ ARE the test plan. The instant you set AC on a story/bug, call
352
+ `derive_test_definition(projectId, ticketId)` — it scaffolds a test-definition
353
+ with **one step per AC** (step = the criterion) and `tests`-links it back, in
354
+ one call. Treat it as the **north star**: create it up front, refine the steps
355
+ as you implement (you'll learn what the AC missed), and `publish` it before
356
+ done (`publish:true` when the target is already `ready`+, else publish later).
357
+ Only hand-build the definition (steps below) when you need steps the AC don't
358
+ express:
359
+
360
+ 1. `ticket_create type=test-definition` — the plan.
361
+ 2. `test_def_step_add` per step (each needs a non-empty `expectedResult`).
362
+ 3. `link_create linkTypeId=tests` from the definition → the story/bug.
363
+ 4. `publish_test_definition` (the target must be `ready`+ first).
364
+ 5. `complete_ticket` on the story/bug.
365
+
366
+ The plan's **content scales with the work**: for user-facing / browser-
367
+ acceptance stories capture the real steps (pan feel, live render, submenu
368
+ visibility, drag feel) and `test_exec_record` an execution so acceptance is an
369
+ artifact. For pure-logic / data-layer / DRY refactors a lightweight definition
370
+ that points at the automated suite ("`node tests/run.js` green covers X") is
371
+ enough — but it must still exist and be published. `technical-task-*`, `epic`,
372
+ `requirement`, `spec-module` are NOT gated. (Lesson from the cmapper double-
373
+ strand: 0 test-defs, 0 executions despite ~40 closed tickets — SM-299 makes
374
+ that impossible.)
375
+
376
+ ---
377
+
378
+ ## 8. Anti-patterns
379
+
380
+ - **Do not** work on anything without a ticket. About to touch files for a
381
+ non-trivial change and no ticket covers it? Pause, create one, get
382
+ acknowledgement, THEN code.
383
+ - **Do not** pick the next ticket autonomously. After finishing, stop, read the
384
+ backlog by `sortOrder` (or `next_actionable`), name the candidate, **ask**.
385
+ - **Do not** skip the Map-Check before substantial actions. Acting on a stale
386
+ snapshot ends in undo.
387
+ - **Do not** build first and back-fill the ticket, or mark a ticket `done`
388
+ before it's merged + independently reviewed. Walk the workflow as you go;
389
+ `review` ≠ `done`.
390
+ - **Do not** name Process Steps after team stages (Design/Build/Test) or layers
391
+ (Frontend/Backend) — those are statuses, not the customer-journey axis. And
392
+ don't use too few/coarse steps: decompose the journey BEFORE placing epics.
393
+ - **Do not** name releases by time ("Now"/"Future") or fold unrelated work into
394
+ a thematically-named release. Content names, content coherence, atomic steps.
395
+ - **Do not** call `change_ticket_status: done` directly. Use `complete_ticket`
396
+ so the DoD + governance gates fire with clean `kind` errors.
397
+ - **Do not** try to `complete_ticket` a `user-story`/`bug` without a **published,
398
+ `tests`-linked test-definition** — the gate blocks it (`MISSING_TEST_DEFINITION`,
399
+ 422). Write the test plan (create test-definition → steps → `link_create tests`
400
+ → `publish_test_definition`) BEFORE, not "done, please review". Don't just tick
401
+ `dod-tests` — that's the unrecorded verbal claim SM-299 exists to stop.
402
+ - **Do not** `ticket_delete` work you decided not to build — that hides it.
403
+ `cancel_ticket` instead (stays visible with history; cancelling an epic
404
+ cascades to its open stories). Delete is for genuine mistakes only.
405
+ - **Do not** create tickets in non-backlog statuses (backlog-start is enforced).
406
+ - **Do not** try to move/complete an epic via any status tool — epic status is
407
+ derived from its stories (`kind=EPIC_STATUS_DERIVED`). Advance the **stories**
408
+ and the epic rolls up on its own.
409
+ - **Do not** assume the default workflow. `get_config` (`section: workflow`,
410
+ optionally `type=`) first — and a gate is N/A if the type hides its field
411
+ (the lockstep).
412
+ - **Do not** read `position.epicId` to find a story's epic — it's always `null`.
413
+ Use `list_links_for_ticket(story, backward)` or `list_tickets(epicId=…)`.
414
+ - **Do not** pass `prerequisites`/`steps`/`links` arrays through
415
+ `ticket_create`/`ticket_update` — the MCP bridge silently drops them. Use the
416
+ dedicated `test_def_step_add` / `link_create` tools. (`acceptanceCriteria` is
417
+ the exception: it has a structured, bridge-safe schema — settable at
418
+ `ticket_create` and `ticket_update`. AC items use key `text`, never `label`.)
419
+ - **Do not** put acceptance criteria as prose in the description — they belong in
420
+ `acceptanceCriteria[]` (settable at `ticket_create`). Migrate prose AC before
421
+ doing anything else with the ticket.
422
+ - **Do not** edit `sortOrder` via `ticket_update` — use `reorder`. Don't
423
+ hand-loop a status change when `bulk_change_status` fits.
424
+ - **Do not** restructure aggressively without `list_revisions` /
425
+ `list_links_for_ticket` first — you may erase context or break a dependency.
426
+ - **Do not** leave related tickets unlinked, or abuse `relates-to` when a
427
+ specific type (`predecessor-of`, `blocks`, `contains`) carries the behaviour.
428
+ - **Do not** pause after every pure-data-layer story (auto-complete in a bundle
429
+ when tests are green); UI stories still pause for smoke.
430
+ - **Do not** assume a write succeeded just because the tool returned — surface
431
+ any `error`/`kind` (a per-type override or gate may have blocked it).
432
+ - **Do not** treat a `test-definition` as carrying an outcome, reuse a
433
+ `test-execution` for a second run, force a pending execution to `done`, or
434
+ `complete_ticket` a feature without a passing execution on its linked
435
+ definition. (Test-loop detail → `reference/spec-evolution.md`.)
436
+ - **Do not** mass-create epics + stories silently. Pause after the outline — the
437
+ animations are designed for human-paced review.
438
+
439
+ ---
440
+
441
+ ## TL;DR
442
+
443
+ The Story Mapper is an agent-first planning + execution surface, not a CRUD
444
+ database. I am the acting instance; the human directs, reviews, and owns the
445
+ queue. The Story Map plans **features** (user value, along the customer's
446
+ journey) — never engineering phases; the Kanban tracks status; the Dependency
447
+ view shows what blocks what. Every substantial activity goes through a
448
+ **ticket**, walked through the workflow as I build (`review` ≠ `done`); priority
449
+ is the backlog `sortOrder`. Do a **Map-Check** (`list_tickets status="backlog"`,
450
+ `compact:true`) — or `next_actionable` — before picking the next thing,
451
+ **propose it, wait**. **Link as you plan** (`link_create`) and check
452
+ `list_links_for_ticket` before reorganising. Epic membership is a `contains`
453
+ link — `position.epicId` reads back null. Gates are declarative: hiding a field
454
+ for a type disables its gate (the lockstep). Use **`mark_ready`** /
455
+ **`complete_ticket`** to make gate failures loud, **`reorder`** to move/rank,
456
+ **`bulk_*`** for fan-out. Auto-complete pure-data stories in a bundle; pause for
457
+ UI smoke. Releases are content-named, process steps atomic. Deep detail is in
458
+ `reference/` — read the relevant file when a task goes past this core.
@@ -0,0 +1,196 @@
1
+ # Anatomy — concepts in detail
2
+
3
+ > Reference for the Story Mapper skill. Read on demand when you need the full
4
+ > model of a concept; the core SKILL.md (§2) carries only the index.
5
+
6
+ ### Project
7
+ Top-level container. Has an `id`, a display `name`, a `ticketPrefix` (e.g.
8
+ `ANI`, used as `ANI-1`, `ANI-2`, …), a `workflow`, a Kanban `boards` config, an
9
+ `entityTypeConfig`, a `linkTypes` catalogue, a `governance` config, a
10
+ `definitions` block (DoR/DoD templates), and the lists: tickets, releases,
11
+ processSteps, revisions. Patch the header with `project_update`; the dedicated
12
+ `set_config` sections are sugar for the sub-objects.
13
+
14
+ ### Release
15
+ A row in the story map; a **product version** — a vehicle for "what ships
16
+ *together* as version N". Has a `name` (`v1.0`, `2026-Q2`), an optional date
17
+ range, and a `status` (`planning` / `active` / `completed` / `cancelled`). The
18
+ filter can hide completed releases so finished scope stops cluttering the map.
19
+
20
+ A release **bundles many features** — that is its whole point. Do NOT create one
21
+ release per feature/epic; that turns the release axis into a duplicate of the
22
+ epic axis and destroys the "what ships as a version" meaning. Many epics share
23
+ one release row. Create a *new* release only for a genuine new version/milestone,
24
+ then drop several epics/stories into it. (Releases are the time/version axis;
25
+ process steps are the user-journey axis — keep them distinct.)
26
+
27
+ ### Process Step
28
+ A column on the story map's backbone. Pure flow-of-value label, not a status.
29
+ Names describe *what happens* for the user, not *who's working* (good: *Onboard*,
30
+ *Configure*; less good: *Backend*, *Frontend* — those fragment a feature across
31
+ many cells). See the paradigm note in the core skill.
32
+
33
+ ### Tickets and their types
34
+ A ticket lives at a `(release, processStep, epic)` position OR in the backlog
35
+ (all three null). Seven default types:
36
+
37
+ - **epic** — the only container type. Lives in a cell; holds stories via a
38
+ `contains` link (see *Epic membership* below). No DoR/DoD by default. Use when
39
+ a feature is too large for a sprint and benefits from breakdown.
40
+ - **user-story** — sprint-sized, user-facing increment. The bread-and-butter
41
+ ticket. DoR and DoD apply.
42
+ - **bug** — fix to existing behaviour. Often configured to bypass DoR — check
43
+ the per-type workflow before assuming.
44
+ - **technical-task-backend / technical-task-ui** — work not directly visible to
45
+ the user but needed (refactor, infra, plumbing). Treat like a story for
46
+ DoR/DoD purposes.
47
+ - **test-definition** — reusable test spec. Carries `prerequisites[]` +
48
+ `steps[]` (each `step` / `data` / `expectedResult`). Carries NO outcome —
49
+ definitions are templates, runnable arbitrarily often. Links to the
50
+ feature/bug it validates via a `tests` link. AC + DoR + DoD sections are hidden
51
+ by default (the prereqs + steps ARE its completeness criteria).
52
+ - **test-execution** — a single run of a definition. Carries `executionSteps[]`
53
+ (frozen clone of the definition's steps + per-step `actualResult` +
54
+ `status: pending|passed|failed|blocked|skipped` + optional `note`) plus
55
+ `runAt`, `runBy`, `env`, and optional `outcomeOverride`. Linked to its
56
+ definition via an `executes` link (auto-created by `test_exec_start`). The
57
+ card surfaces the outcome as a colour-coded pill.
58
+
59
+ `ticketTypes` is configurable per project — if the user has custom types,
60
+ respect them rather than mapping onto the defaults.
61
+
62
+ ### Epic membership = a `contains` link (SM-52)
63
+ A story belongs to an epic through a `contains` link (epic → story), **not** a
64
+ stored field. `position.epicId` is *accepted as input* on `ticket_create` and on
65
+ `reorder`'s `scope` (the engine creates the link for you), but it is
66
+ **stripped to null on persist** — reading `ticket.position.epicId` back gives
67
+ `null`. To find a story's epic, use `list_links_for_ticket(story, backward)` or
68
+ `list_tickets(epicId=<epic>)` (that filter resolves through the `contains`
69
+ graph). When a story is assigned to an epic it **inherits the epic's
70
+ release + processStep** (SM-67) — you don't set those separately.
71
+
72
+ ### Status (workflow lanes)
73
+ A ticket's lifecycle position. Default statuses: `backlog → ready →
74
+ in-progress → review → done`. Each status is an object `{id, name, category}`
75
+ where *category* ∈ `todo | doing | blocked | done` — the UI uses it for styling
76
+ and for suggesting Kanban-column groupings.
77
+
78
+ Tickets ALWAYS start in `backlog`. There's no shortcut into other statuses on
79
+ create — every move is an explicit transition.
80
+
81
+ **Test-execution exception (auto-coupling):** a `test-execution` ticket's status
82
+ auto-syncs with its outcome. It spawns in `in-progress`; once the effective
83
+ outcome flips to anything non-pending (every step has a status, or
84
+ `outcomeOverride` is set), status auto-advances to `done`. Reverting a step to
85
+ `pending` flips status back to `in-progress`. The coupling only owns the
86
+ `in-progress ↔ done` axis — manual `backlog`/`ready`/`review` are untouched.
87
+ Don't fight it: never manually set a test-execution to `done` while steps are
88
+ pending (the auto-flip reverts it); use `outcomeOverride` to call the run.
89
+
90
+ ### Workflow + Transitions + the rule engine
91
+ A workflow has `statuses[]` and `transitions[]`. A transition is named (e.g.
92
+ *Start Progress*, *Cancel*) and declares:
93
+
94
+ - `toStatus` — where it lands.
95
+ - `fromStatuses[]` + `allowFromAny` — which sources can use it.
96
+ - `requireGate: "DoR" | "DoD" | null` — quality gate enforced on the move.
97
+
98
+ Per-type overrides exist (`workflow.byType[type].transitions`): a bug type can
99
+ disable the DoR gate without affecting stories.
100
+
101
+ Gates run through a **declarative rule catalog** (SM-102). `requireGate` maps to
102
+ catalog rules; two **global rules** apply to every forward transition on top of
103
+ the matched transition's own (each self-limits via the transition context):
104
+
105
+ - a **test-definition** must have ≥1 outbound `tests` link before leaving
106
+ backlog (`kind: "TEST_TARGETS"`);
107
+ - a **test-execution** must have a non-pending outcome before entering a
108
+ `done`-category status (`kind: "TEST_OUTCOME"`).
109
+
110
+ **The lockstep invariant (internalise this):** a gate is **N/A for a type when
111
+ that type hides the backing field** via `entityTypeConfig`. Hiding a field
112
+ doesn't only hide UI — it disables the matching gate:
113
+
114
+ | field hidden (`entityTypeConfig`) | gate that goes N/A |
115
+ |---|---|
116
+ | `showDefinitionOfReady: false` | DoR |
117
+ | `showDefinitionOfDone: false` | DoD |
118
+ | `showTestOutcome: false` | test-execution outcome |
119
+
120
+ So if a `change_ticket_status`/`complete_ticket` you expected to be gated sails
121
+ through, check whether the type hides that field. The read-only **Rules** tab in
122
+ Settings lists which rules are active per type.
123
+
124
+ Two transition rules to internalise:
125
+
126
+ 1. **Skip-moves only check the matched transition's gate** — not every crossed
127
+ status's gate. `backlog → done` with gate=DoD checks DoD only. This is the
128
+ "Jira-rein" semantics — the user must define an explicit transition for the
129
+ move to be allowed at all.
130
+ 2. **Reverse moves (toStatus index ≤ current index) are ungated** — reopening is
131
+ always permitted.
132
+
133
+ ### Definition of Ready / Definition of Done
134
+ Templates on the project; *frozen copies* on each ticket. Items are checklists
135
+ with `required: true/false`. When a transition's `requireGate` fires, ALL
136
+ required items in the relevant block must be checked or the move is blocked with
137
+ `kind: "DoR" | "DoD", missing: [...]`. Project-level template changes do NOT
138
+ retroactively touch open tickets — only newly created tickets pick them up.
139
+
140
+ ### entityTypeConfig (per-type field visibility)
141
+ `project.entityTypeConfig[type]` controls which sections a type shows AND, via
142
+ the lockstep above, which gates apply. Flag set (defaults in parentheses):
143
+
144
+ - `showAcceptanceCriteria` (true; false for test types)
145
+ - `showDefinitionOfReady` / `showDefinitionOfDone` (true; false for test types)
146
+ - `allowParentEpic` (true; **always false for `epic`**)
147
+ - `showProcessStep` / `showRelease` / `showLinks` (true)
148
+ - `showPrerequisites` / `showSteps` (test-definition only)
149
+ - `showExecutionSteps` / `showTestOutcome` (test-execution only)
150
+
151
+ Test-flags are hard-locked to their type — you can't switch on
152
+ `showPrerequisites` for a story.
153
+
154
+ ### Board (Kanban Columns)
155
+ `project.boards.kanban.columns` is the column layout. Each column has `id`,
156
+ `name`, `statusIds[]` — a column may bundle multiple statuses into one lane
157
+ (e.g. *In Progress* bundling `in-progress` + `review`). Default = 1 column per
158
+ status. Statuses in no column show up as a synthetic trailing "orphan" lane so
159
+ nothing is hidden.
160
+
161
+ ### Typed links + the Dependency view
162
+ Beyond the structural epic→story containment, tickets carry **typed links** to
163
+ other tickets. The catalogue lives in `project.linkTypes`. **Semantics matter** —
164
+ the type carries behaviour (cycle-checks, graph direction), it's not just a label:
165
+
166
+ | id | inverse | semantic | cycle-checked | typical use |
167
+ |---|---|---|---|---|
168
+ | `predecessor-of` | Successor of | precedence | ✅ | "must finish before" ordering |
169
+ | `blocks` | Blocked by | blocking | ✅ | "can't start until" hard dependency |
170
+ | `follows-on` | Precedes | sequence | — | softer linear chain |
171
+ | `contains` | Contained by | containment | ✅ | epic → story (canonical, SM-52) |
172
+ | `relates-to` | Relates to | freeform | — | symmetric "see also" |
173
+ | `executes` | Executed by | validation | — | test-execution → definition |
174
+ | `tests` | Tested by | validation | — | test-definition → feature |
175
+ | `modifies` | Modified by | freeform | ✅ | spec-change ticket → original |
176
+ | `supersedes` | Superseded by | supersession | ✅ | newer epic obsoletes the older version (drives the cross-release product-doc fold) |
177
+ | `replaces` | Replaced by | supersession | ✅ | a ticket replaces another |
178
+ | `refines` | Refined by | freeform | ✅ | adds detail without obsoleting |
179
+ | `realises` | Realised by | freeform | — | a ticket realises a PRD requirement/anchor (direction A) |
180
+
181
+ Cycle-checked semantics (precedence, blocking, containment, plus `modifies` via
182
+ an explicit flag) reject an edge that would close a loop (`kind: "LINK_CYCLE"`).
183
+ Containment is created via `position.epicId` at create time, NOT via
184
+ `link_create`; read it via `list_links_for_ticket` or the Dependency view, never
185
+ via `ticket.position.epicId`.
186
+
187
+ **The Dependency view** (third view next to Map and Kanban) renders all tickets
188
+ as a layered DAG. Use it to: see **what depends on this ticket** (downstream
189
+ impact / forward edges); see **what this ticket waits on** (upstream blockers /
190
+ backward edges); trace a feature epic → contained stories → implementing
191
+ tickets (the chain documents WHY each ticket exists); spot orphan tickets (no
192
+ edges — often a smell that something should have been linked). It's read-only.
193
+
194
+ **Link as you plan** — typed links + the Dependency view are the planning
195
+ surface, not an afterthought. Prefer the specific type (`blocks`,
196
+ `predecessor-of`) over generic `relates-to`.