kataster 0.3.1 → 0.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.
Files changed (89) hide show
  1. package/.claude/THIRD_PARTY_NOTICES.md +4 -0
  2. package/.claude/agents/acceptance-tester.md +7 -2
  3. package/.claude/agents/code-reviewer.md +7 -2
  4. package/.claude/agents/domain-architect.md +7 -3
  5. package/.claude/agents/researcher.md +77 -0
  6. package/.claude/agents/ux-designer.md +42 -47
  7. package/.claude/hooks/validate-docs.ts +17 -1
  8. package/.claude/lib/architecture.ts +3 -33
  9. package/.claude/lib/backlog.ts +2 -0
  10. package/.claude/lib/config.ts +49 -0
  11. package/.claude/lib/discovery.ts +200 -32
  12. package/.claude/lib/engineering.ts +18 -6
  13. package/.claude/lib/gaps.ts +179 -0
  14. package/.claude/lib/glob.ts +39 -0
  15. package/.claude/lib/repo.ts +143 -19
  16. package/.claude/lib/research.ts +303 -0
  17. package/.claude/lib/slices.ts +529 -0
  18. package/.claude/package.json +1 -0
  19. package/.claude/settings.json +2 -2
  20. package/.claude/skills/adopt/SKILL.md +111 -34
  21. package/.claude/skills/adopt/scripts/gap-register.ts +61 -0
  22. package/.claude/skills/adopt/scripts/repo-map.ts +34 -2
  23. package/.claude/skills/adopt/scripts/slice-doc.ts +117 -0
  24. package/.claude/skills/adopt/scripts/slice.ts +163 -0
  25. package/.claude/skills/adopt/templates/context-map.as-is.md +22 -0
  26. package/.claude/skills/architect/SKILL.md +6 -1
  27. package/.claude/skills/backlog/SKILL.md +2 -2
  28. package/.claude/skills/bootstrap/SKILL.md +9 -7
  29. package/.claude/skills/domain-model/CONTEXT-FORMAT.md +1 -1
  30. package/.claude/skills/domain-model/SKILL.md +24 -4
  31. package/.claude/skills/event-storming/SKILL.md +3 -2
  32. package/.claude/skills/event-storming/schema/events.schema.json +2 -0
  33. package/.claude/skills/event-storming/templates/events.example.yaml +6 -0
  34. package/.claude/skills/feature/SKILL.md +16 -13
  35. package/.claude/skills/feature/scripts/intake.ts +1 -1
  36. package/.claude/skills/grilling/SKILL.md +15 -0
  37. package/.claude/skills/groom-backlog/SKILL.md +19 -17
  38. package/.claude/skills/implement/SKILL.md +199 -78
  39. package/.claude/skills/implement/scripts/characterize.ts +252 -0
  40. package/.claude/skills/implement/scripts/check-scenarios.ts +1 -1
  41. package/.claude/skills/implement/scripts/story-context.ts +65 -1
  42. package/.claude/skills/implement/scripts/verify.ts +4 -1
  43. package/.claude/skills/improve-codebase-architecture/SKILL.md +4 -1
  44. package/.claude/skills/prototype/SKILL.md +1 -1
  45. package/.claude/skills/research/SKILL.md +149 -0
  46. package/.claude/skills/research/scripts/research-check.ts +105 -0
  47. package/.claude/skills/research/templates/research.md +29 -0
  48. package/.claude/skills/review-stories/SKILL.md +49 -19
  49. package/.claude/skills/shape/SKILL.md +26 -7
  50. package/.claude/skills/tdd/SKILL.md +10 -0
  51. package/.claude/skills/user-stories/SKILL.md +128 -51
  52. package/.claude/skills/user-stories/schema/story.schema.json +10 -3
  53. package/.claude/skills/user-stories/scripts/lint-story.ts +56 -0
  54. package/.claude/skills/user-stories/templates/story-template.md +6 -2
  55. package/.claude/skills/ux-design/SKILL.md +9 -7
  56. package/.opencode/agents/acceptance-tester.md +8 -3
  57. package/.opencode/agents/code-reviewer.md +8 -3
  58. package/.opencode/agents/domain-architect.md +7 -3
  59. package/.opencode/agents/researcher.md +91 -0
  60. package/.opencode/agents/ux-designer.md +42 -52
  61. package/.opencode/commands/adopt.md +1 -1
  62. package/.opencode/commands/bootstrap.md +1 -1
  63. package/.opencode/commands/feature.md +1 -1
  64. package/.opencode/commands/groom-backlog.md +1 -1
  65. package/.opencode/commands/implement.md +1 -1
  66. package/.opencode/commands/research.md +7 -0
  67. package/.opencode/commands/review-stories.md +1 -1
  68. package/.opencode/commands/shape.md +1 -1
  69. package/AGENTS.md +30 -0
  70. package/CHANGELOG.md +73 -0
  71. package/README.md +108 -24
  72. package/guide/brownfield.md +41 -12
  73. package/guide/concepts.md +23 -6
  74. package/guide/greenfield.md +4 -3
  75. package/package.json +1 -1
  76. package/src/cli.mjs +42 -4
  77. package/src/detect.mjs +9 -0
  78. package/src/install.mjs +66 -6
  79. package/templates/docs/domain/context-map.md +5 -1
  80. package/templates/docs/domain/events.yaml +3 -0
  81. package/templates/docs/research/README.md +70 -0
  82. package/templates/docs/stories/README.md +12 -3
  83. package/templates/docs/workflow.md +76 -19
  84. package/.claude/agents/lead-dev.md +0 -52
  85. package/.claude/agents/product-owner.md +0 -39
  86. package/.claude/agents/requirements-engineer.md +0 -44
  87. package/.opencode/agents/lead-dev.md +0 -69
  88. package/.opencode/agents/product-owner.md +0 -59
  89. package/.opencode/agents/requirements-engineer.md +0 -58
@@ -0,0 +1,22 @@
1
+ # As-is context map – {{project}}
2
+
3
+ > Recovered from code by `/adopt` on {{date}} at {{commit}}. This is **not a target**.
4
+ > Target: [context-map.md](context-map.md) · Gap register: [gap-register.md](gap-register.md).
5
+
6
+ <!--
7
+ One section per recovered bounded context. Use `### BC-… – <name>` so gap-register.ts can link to it.
8
+ Evidence is a table, a service method or a path; no target statements, no invented terms.
9
+ -->
10
+
11
+ ```mermaid
12
+ flowchart LR
13
+ %% BC-ExampleA -->|recovered dependency| BC-ExampleB
14
+ ```
15
+
16
+ ## Contexts
17
+
18
+ ### BC-Example – <name>
19
+ Purpose (as recovered): …
20
+ Core terms: …
21
+ Evidence: `<path:line>`, `<table>`, `<service method>`.
22
+ Boundaries: …
@@ -21,10 +21,15 @@ Domain language (the glossary in `CONTEXT.md`), bounded contexts, aggregates and
21
21
  ├── architecture/
22
22
  │ └── data-model.md ← logical data model (domain-model skill)
23
23
  └── domain/
24
- ├── context-map.md
24
+ ├── context-map.md ← target map
25
+ ├── context-map.as-is.md ← as-is snapshot, written only by /adopt
26
+ ├── gap-register.md ← as-is ↔ target gaps (generated rows + decisions)
25
27
  └── events.yaml
26
28
  ```
27
29
 
30
+ `docs/domain/context-map.md` is the target; `context-map.as-is.md` is the snapshot recovered by `/adopt`. Do not
31
+ write the as-is map from an architecture session – a target decision belongs in the target map.
32
+
28
33
  Once code exists and contexts live in separate modules, context-specific decisions may move next to the code (`src/<context>/docs/adr/`); system-wide decisions stay in `docs/adr/`.
29
34
 
30
35
  ## During the session
@@ -155,8 +155,8 @@ silently – ask the user.
155
155
 
156
156
  ## When to sync
157
157
 
158
- - after `requirements-engineer` created or changed stories → `push`
159
- - after `product-owner` or `lead-dev` changed `priority`, `size`, `risk`, `depends_on` → `push`
158
+ - after the main session created or changed stories (spec engineer) → `push`
159
+ - after `priority`, `size`, `risk` or `depends_on` changed → `push`
160
160
  - before `/review-stories` → `pull`, then review, then `push` the approved stories
161
161
  - before `/implement` → `pull`; after each status change the workflow updates the tracker (GitHub directly, Jira by
162
162
  the printed MCP transition), and after `done` → `push`
@@ -77,24 +77,26 @@ and reason. Do not let it become a mood board.
77
77
 
78
78
  ## Phase 5 – Foundation stories and the first slice
79
79
 
80
- Delegate to `requirements-engineer` in two parts:
80
+ Write the stories yourself as the spec engineer (the `user-stories` skill is the method), in two parts:
81
81
 
82
82
  1. **Foundation tech tasks** – what every later story relies on: repository skeleton, the single quality command
83
83
  (`verify`), CI, the test harness and test data approach, auth/roles if the vision needs them, deployment.
84
84
  Each is a tech task with a checklist and `depends_on`, not a domain story. Keep them minimal: foundation just
85
85
  in time, not a platform project.
86
86
  2. **The first vertical slice** – the smallest set of stories that delivers one real end-to-end path from the
87
- vision (e.g. "report → triage → resolve"), each a story with Gherkin scenarios, `ui` where a person sees
87
+ vision (e.g. "report → triage → resolve"), each a story with Gherkin scenarios, `ui: true` where a person sees
88
88
  something.
89
89
 
90
- Rules: at most 10 scenarios per story; no implementation plan inside a domain story; every story links its
91
- `events`; `status: draft`, then `review` when finished.
90
+ Rules: one story = one command + its events on one aggregate, at most 4 scenarios; no implementation plan inside a
91
+ domain story; every domain story links `aggregate`, `command` and its `events`; `status: draft`, then `review` when
92
+ finished. The spec linter must be green before `ready-for-human-review`.
93
+
92
94
 
93
95
  ## Phase 6 – Review
94
96
 
95
- Read `.claude/skills/review-stories/SKILL.md` and follow it with the story IDs from Phase 5. The user approves
96
- every `ready`. Fix what the review finds through `requirements-engineer` – never by editing a story into shape
97
- yourself when the change is structural.
97
+ Read `.claude/skills/review-stories/SKILL.md` and follow it with the story IDs from Phase 5. The spec linter is the
98
+ gate; the user approves every `ready`. Fix what it finds in the story (or in the model, when an event or aggregate
99
+ is missing) – never work around a lint error.
98
100
 
99
101
  ## Phase 7 – Wrap-up
100
102
 
@@ -42,6 +42,6 @@ _Avoid_: Fix, service
42
42
 
43
43
  ## Single vs multi-context
44
44
 
45
- During discovery there is one root `CONTEXT.md`, grouped by bounded context; the relationships between contexts are in `docs/domain/context-map.md`.
45
+ During discovery there is one root `CONTEXT.md`, grouped by bounded context; the relationships between contexts are in `docs/domain/context-map.md` (target). `/adopt` records what the code does today in `docs/domain/context-map.as-is.md` – not a target.
46
46
 
47
47
  When code exists and contexts become separate modules, the glossary may be split: a root `CONTEXT-MAP.md` lists the contexts and links to one `CONTEXT.md` per module (e.g. `src/workshop/CONTEXT.md`). Only split when the code is actually structured that way – decide it via ADR.
@@ -15,7 +15,9 @@ Architecture decisions (ADRs, tech stack) belong to the `architect` skill. The d
15
15
  |---|---|
16
16
  | Glossary (ubiquitous language) | `CONTEXT.md` at the repo root – format: [CONTEXT-FORMAT.md](./CONTEXT-FORMAT.md) |
17
17
  | Event storming model incl. `bounded_contexts`, `aggregates` | `docs/domain/events.yaml` |
18
- | Context map | `docs/domain/context-map.md` |
18
+ | Target context map | `docs/domain/context-map.md` – where the domain is going |
19
+ | As-is context map | `docs/domain/context-map.as-is.md` – recovered from code, written only by `/adopt` |
20
+ | Gap register | `docs/domain/gap-register.md` – links as-is and target, generated rows + user decisions |
19
21
  | Logical data model | `docs/architecture/data-model.md` – template: `templates/data-model.md` |
20
22
 
21
23
  ## 1. Language (during every session)
@@ -30,7 +32,7 @@ When the user uses vague or overloaded terms, propose a precise canonical term.
30
32
  When domain relationships are being discussed, stress-test them with specific scenarios. Invent scenarios that probe edge cases and force the user to be precise about the boundaries between concepts. "A customer reports the same problem on an item that already has an open case – a new case or the same one?"
31
33
 
32
34
  ### Cross-reference with docs and code
33
- When the user states how something works, check whether `docs/domain/events.yaml`, the stories (and the code, once it exists) agree. If you find a contradiction, surface it.
35
+ When the user states how something works, check whether `docs/domain/events.yaml`, the stories (and the code, once it exists) agree. If you find a contradiction, surface it. A source that contradicts the model is a grilling question, not a silent rewrite of the model (see the `research` skill).
34
36
 
35
37
  ### Update CONTEXT.md inline
36
38
  When a term is resolved, update `CONTEXT.md` right there. Don't batch these up: capture them as they happen. `CONTEXT.md` is totally devoid of implementation details. It is a glossary and nothing else – not a spec, not a scratch pad.
@@ -39,7 +41,8 @@ Same word, different meaning in two places → a hint at a bounded context bound
39
41
 
40
42
  ## 2. Bounded Contexts & Context Map
41
43
  - Draw boundaries along language (same word, different meaning → different context) and responsibility (who decides?).
42
- - `docs/domain/context-map.md`: per context its purpose, core terms, owner role. Relationships as a Mermaid `flowchart` using the patterns Customer/Supplier, Conformist, Anti-Corruption Layer, Shared Kernel, Published Language.
44
+ - `docs/domain/context-map.md` is the **target** map: per context its purpose, core terms, owner role. Relationships as a Mermaid `flowchart` using the patterns Customer/Supplier, Conformist, Anti-Corruption Layer, Shared Kernel, Published Language.
45
+ - `docs/domain/context-map.as-is.md` is the **as-is** snapshot: what the code does today, with evidence. Only `/adopt` writes it; every other discovery path writes the target. The gap register links both.
43
46
  - 2–4 contexts are typical for a small system. More only with justification.
44
47
  - Maintain them in `events.yaml` under `bounded_contexts`, and group the terms in `CONTEXT.md` by context.
45
48
 
@@ -47,9 +50,26 @@ Same word, different meaning in two places → a hint at a bounded context bound
47
50
  - An aggregate protects invariants that must be consistent **immediately**. Everything else is eventually consistent via events/policies.
48
51
  - Keep them small. Reference other aggregates by ID only.
49
52
  - Per aggregate in `events.yaml`: `context`, `invariants` (as testable statements). Assign commands and events via `aggregate`.
50
- - **An invariant is stated once, on the aggregate** (user, 2026-10-01). A command's `rules` list only what it adds beyond them: defaults, actor permissions no invariant carries, required input, checks across aggregate or context boundaries, and consequences of the transition. Everything the stored state has to satisfy is an invariant, not a rule – the requirements-engineer reads both when deriving scenarios.
53
+ - **An invariant is stated once, on the aggregate** (user, 2026-10-01). A command's `rules` list only what it adds beyond them: defaults, actor permissions no invariant carries, required input, checks across aggregate or context boundaries, and consequences of the transition. Everything the stored state has to satisfy is an invariant, not a rule – the spec engineer reads both when deriving scenarios.
51
54
  - Sign of a wrong aggregate: a command needs data from several aggregates to check a rule.
52
55
 
56
+ ### Aggregate status: target, as-is, unresolved
57
+ Every aggregate carries a status; a missing `status` means `target`, so existing models stay valid.
58
+
59
+ | Status | Meaning | Rule |
60
+ |---|---|---|
61
+ | `target` | The boundary the project wants. The default in greenfield and in a confirmed target model. | Only a user decision makes an inferred boundary `target`. |
62
+ | `as-is` | The factual consistency boundary recovered from code. | Requires `evidence`: the table, service method or path that marks it. |
63
+ | `unresolved` | The boundary is unclear. | Requires an open hotspot (`refs: [AGG-…]`) and grilling. No story on it can become ready. |
64
+
65
+ **Prefer `as-is` or `unresolved` over an invented aggregate.** `/adopt` never writes `target` for something it
66
+ inferred from code. If you cannot name the table, method or path that holds the boundary together, it is not
67
+ `as-is` – it is `unresolved`. After changing a status or evidence, refresh the gap register:
68
+
69
+ ```bash
70
+ node .claude/skills/adopt/scripts/gap-register.ts
71
+ ```
72
+
53
73
  ## 4. Logical Data Model (`docs/architecture/data-model.md`)
54
74
  - Per aggregate: root entity, entities, value objects, attributes with **domain** types (e.g. `SerialNumber`, `Money`, `Timestamp`), required/optional.
55
75
  - Lifecycle as a Mermaid `stateDiagram-v2` (derive states from the events).
@@ -12,7 +12,8 @@ Focus of this session: the arguments from the invocation (empty = big picture ac
12
12
 
13
13
  ## Preparation
14
14
  1. Call the `skill` tool for `grilling` and `domain-model`. Grilling sets how you ask questions; domain-model sets how you guard the language in `CONTEXT.md`.
15
- 2. Read `docs/product/vision.md`, `CONTEXT.md`, `docs/domain/events.yaml`, `docs/domain/context-map.md`.
15
+ 2. Read `docs/product/vision.md`, `CONTEXT.md`, `docs/domain/events.yaml`, `docs/domain/context-map.md` (target),
16
+ `docs/domain/context-map.as-is.md` and `docs/domain/gap-register.md` when they exist.
16
17
  3. Format reference: `templates/events.example.yaml` in this skill folder (unrelated example domain – copy the format only, no content).
17
18
 
18
19
  ## Facilitation Rules
@@ -33,7 +34,7 @@ Focus of this session: the arguments from the invocation (empty = big picture ac
33
34
  4. **Commands & actors** – What triggers each event, and who does it? Capture external systems (`EXT-`). Business rules of the command go into `rules` – only what the command adds beyond the `invariants` of its aggregate, which are stated once, there (user, 2026-10-01).
34
35
  5. **Policies** – "Whenever <event>, then <command>". Include time-triggered ones (event with `origin: time`) and manual routines.
35
36
  6. **Read models** – What information does an actor need to trigger the command? (`fed_by`, `used_by`, `fields`)
36
- 7. **Aggregates (proposal)** – Which rules must be protected consistently? Rough assignment of commands/events. Detailed work is done by `domain-architect`.
37
+ 7. **Aggregates (proposal)** – Which rules must be protected consistently? Rough assignment of commands/events. Detailed work is done by `domain-architect`. Every aggregate gets `status: target` in greenfield; a boundary the user cannot settle becomes `status: unresolved` with an open hotspot. When adopting existing code, the status is `as-is` (with evidence) or `unresolved`, never an invented `target`.
37
38
  8. **Bounded contexts (proposal)** – Where do language or responsibility change? Propose rough boundaries.
38
39
 
39
40
  When focusing on a single process: phases 0–6 for that process (phase 0 only for what the vision doesn't cover yet), 7–8 only if something new emerges.
@@ -51,6 +51,8 @@
51
51
  "id": { "type": "string", "pattern": "^AGG-[A-Za-z0-9]+$" },
52
52
  "name": { "$ref": "#/$defs/text" },
53
53
  "context": { "type": "string" },
54
+ "status": { "enum": ["target", "as-is", "unresolved"] },
55
+ "evidence": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/text" } },
54
56
  "invariants": { "type": "array", "items": { "$ref": "#/$defs/text" } },
55
57
  "description": { "type": "string" }
56
58
  }
@@ -24,12 +24,18 @@ aggregates:
24
24
  - id: AGG-Bike
25
25
  name: Bike
26
26
  context: BC-Rental
27
+ status: target
27
28
  invariants:
28
29
  - A bike can only be rented out once at a time
29
30
  - A bike marked as damaged cannot be rented out
30
31
  - id: AGG-RepairOrder
31
32
  name: Repair order
32
33
  context: BC-Workshop
34
+ # status: as-is # factual boundary recovered from code; add evidence below
35
+ # evidence:
36
+ # - repair_orders table (db/schema.sql:40)
37
+ # - RepairOrderService.open() (src/services/repairOrderService.ts:22)
38
+ # status: unresolved # boundary unclear; add an open hotspot with refs: [AGG-RepairOrder]
33
39
 
34
40
  events:
35
41
  - id: EVT-BikeRented
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: feature
3
- description: Entry point for a new feature or change once the initial discovery is done – accepts a free-text idea, an existing story (`ST-NNN`) or a ticket (`#123`, `PROJ-123`, URL), grills the idea, runs a focused event storming, updates domain model and ADRs, derives stories into the backlog (local, or the tracker mirror) and runs the story review; bug tickets go to a regression story instead; `--prototype` adds a throwaway prototype before the stories.
3
+ description: Entry point for a new feature or change once the initial discovery is done – accepts a free-text idea, an existing story (`ST-NNN`) or a ticket (`#123`, `PROJ-123`, URL), grills the idea, runs a focused event storming, updates domain model and ADRs, derives stories into the backlog (local, or the tracker mirror) and runs the story review; bug tickets go to a regression story instead; `--prototype` adds a throwaway prototype before the stories; `--research` forces the research step for a cross-cutting question.
4
4
  disable-model-invocation: true
5
- argument-hint: "<idea | ST-NNN | #issue | PROJ-123 | URL> [--prototype[=ui|logic]]"
5
+ argument-hint: "<idea | ST-NNN | #issue | PROJ-123 | URL> [--prototype[=ui|logic]] [--research]"
6
6
  ---
7
7
 
8
8
  # New Feature
@@ -11,6 +11,8 @@ The argument is a feature idea, an existing story or a ticket. Empty → ask the
11
11
  Pick a short kebab-case slug for it (e.g. `order-photos`); stories get the label `feature:<slug>`.
12
12
  `--prototype[=ui|logic]` is a flag, not part of the idea: strip it before resolving a reference. It asks for a
13
13
  prototype before the stories are written; without a branch the `prototype` skill picks it from the question.
14
+ `--research` is a flag too: strip it before resolving a reference. It forces the research step for a topic the
15
+ trigger list in step 2 does not catch.
14
16
 
15
17
  ## 0. Intake – when the argument is a reference
16
18
 
@@ -57,14 +59,15 @@ ADRs and `docs/product/ux-guidelines.md` first.
57
59
  Do not run an event storming for a bug and do not create a feature slug unless the rule changes.
58
60
 
59
61
  ## 1. Preparation
60
- Read `docs/product/vision.md`, `CONTEXT.md`, `docs/domain/events.yaml`, `docs/domain/context-map.md`, `docs/architecture/data-model.md`, `docs/adr/`, `docs/stories/BACKLOG.md`. Find out what already exists for this idea (events, stories, hotspots) before asking anything. With an intake result, use its source and matching story instead of searching from scratch. If a linked story exists, pull the tracker first (`/backlog-sync pull`) so the mirror is current.
62
+ Read `docs/product/vision.md`, `CONTEXT.md`, `docs/domain/events.yaml`, `docs/domain/context-map.md` (target), `docs/domain/context-map.as-is.md`, `docs/domain/gap-register.md`, `docs/architecture/data-model.md`, `docs/adr/`, `docs/stories/BACKLOG.md`. Find out what already exists for this idea (events, stories, hotspots) before asking anything. With an intake result, use its source and matching story instead of searching from scratch. If a linked story exists, pull the tracker first (`/backlog-sync pull`) so the mirror is current.
61
63
 
62
64
  ## 2. Grill the idea
63
- Call the `skill` tool four times, for `grilling`, `domain-model`, `architect` and `ux-design` (the first three are the set of `/grill-with-docs`, which can't be called from a skill). Grill the user until the frontier is empty and they confirm a shared understanding. The grilling carries the three perspectives the story review later only checks – product owner, lead dev, UX. With an intake result, the ticket's claims and the intake's `signals` seed the frontier; unresolved comments and contradictions are the first questions. Typical branches:
64
- - **PO**: Which problem, for which user group, and what value? Measurable outcome? Does it fit the vision, or touch a non-goal? If it changes scope → update `docs/product/vision.md` with the user. Must vs. could – what ships first?
65
- - **Lead dev**: Which existing code, data and stories change? Is there a migration? What is hard to test? Where does it cut into stories – each a vertical slice of at most ~10 scenarios?
65
+ Call the `skill` tool four times, for `grilling`, `domain-model`, `architect` and `ux-design` (the first three are the set of `/grill-with-docs`, which can't be called from a skill). Grill the user until the frontier is empty and they confirm a shared understanding. The grilling carries the three perspectives the spec linter cannot check – product, engineering, UX. With an intake result, the ticket's claims and the intake's `signals` seed the frontier; unresolved comments and contradictions are the first questions. Typical branches:
66
+ - **Research – does the idea rest on an external fact?** Auth/identity, security, payment, privacy/data protection, accessibility, performance, a new library or technology, or `--research`: load the `research` skill before grilling the affected branch. Check `docs/research/` first; a trigger is not a mandate, and one run covers a topic, not a story. Findings enter the round as cited recommendations – evidence, not decisions.
67
+ - **Product**: Which problem, for which user group, and what value? Measurable outcome? Does it fit the vision, or touch a non-goal? If it changes scope → update `docs/product/vision.md` with the user. Must vs. could – what ships first?
68
+ - **Engineering**: Which existing code, data and stories change? Is there a migration? What is hard to test? Where does it cut into stories – one command per story, at most 4 scenarios?
66
69
  - Which existing processes, events and stories does it change? What's explicitly out of scope?
67
- - **UX – does a person see anything?** Almost always yes – then the UX frontier of `ux-design` belongs in the rounds: entry point, the screen's one job, what is shown before acting, what happens afterwards, the rejected, empty, full and no-permission cases, and the UI wording. A feature whose screens nobody named gets them by accident. Stories with a frontend part get the label `ui`.
70
+ - **UX – does a person see anything?** Almost always yes – then the UX frontier of `ux-design` belongs in the rounds: entry point, the screen's one job, what is shown before acting, what happens afterwards, the rejected, empty, full and no-permission cases, and the UI wording. A feature whose screens nobody named gets them by accident. Stories with a frontend part get `ui: true`.
68
71
  - **Prototype – is paper enough?** When the UX frontier leaves a structural layout choice, a flow or a state model that cannot be settled in words, the UX lens proposes a prototype: one question, the branch (`ui` or `logic`), the variants or scenarios, and a timebox. The user decides. `--prototype` makes it explicit. Do not propose one for polish or for a question a guideline already answers. If it is agreed, run step 2b before the event storming.
69
72
  - New or changed terms → `CONTEXT.md` inline.
70
73
  - An architectural trade-off → ADR (`status: proposed`) only if the architect skill's three criteria hold.
@@ -86,9 +89,9 @@ it. In short:
86
89
  4. **Capture.** The decision goes to `ux-designer` for `docs/product/ux-guidelines.md` (a G-number when it is
87
90
  a recurring rule). Commit `docs/prototypes/<slug>/` on a throwaway branch `prototype/<slug>`, push it only
88
91
  if the user wants to share it, then return to the branch you were on. The branch is never merged.
89
- 5. **Into the story.** Pass the verdict and the branch pointer to `requirements-engineer` in section 5: the
90
- story's `## Context` gets `Prototype: prototype/<slug> – <question> – <verdict>`, and the scenarios reflect
91
- the decision. The `ux-designer` never writes the story itself.
92
+ 5. **Into the story.** In section 5 you write the verdict and the branch pointer into the story's `## Context`:
93
+ `Prototype: prototype/<slug> – <question> – <verdict>`, and the scenarios reflect the decision. The
94
+ `ux-designer` never writes the story itself.
92
95
 
93
96
  If the question needs the real application (an existing page, real data), say so: that is an in-app prototype
94
97
  and belongs to `/implement`, not to discovery. If the prototype does not answer the question within its
@@ -103,10 +106,10 @@ Read `.claude/skills/event-storming/SKILL.md` and follow it with the feature as
103
106
  - A UX decision changes or adds a guideline → delegate to `ux-designer`: write exactly these decisions into `docs/product/ux-guidelines.md`. A prototype verdict is a decision like any other; the branch pointer and the verdict go into the story through step 5. The audit of existing screens belongs to `/groom-backlog`, not to the feature.
104
107
 
105
108
  ## 5. Stories
106
- Delegate to `requirements-engineer`: derive stories for the feature's new or changed commands, policies and read models; name the event/command IDs, the label `feature:<slug>`, the label `ui` for every story with a frontend part, the label `bug` for the bug path, the source reference (`Source: <ref> (<url>)`) for every story derived from a ticket, the UX decisions from step 2 (with the G-numbers of the guidelines they reference), the prototype verdict and branch pointer from step 2b, the story cut from step 2, and existing stories that need revising. Finished stories get `status: review`; have it report the IDs of all stories it created or revised.
109
+ Write the stories yourself as the spec engineer (the `user-stories` skill is the method): derive one story per new or changed command, policy or read model; name `aggregate` and `command` (exactly one each), the event/command IDs, `ui: true` for every story with a frontend part, `type: chore`/`task` for non-domain work, the label `feature:<slug>`, the label `bug` for the bug path, the source reference (`Source: <ref> (<url>)`) for every story derived from a ticket, the research files they cite (`sources: [docs/research/<topic>.md]`) with adopted/rejected findings and their reasons in `## Context`, the UX decisions from step 2 (with the G-numbers of the guidelines they reference), the prototype verdict and branch pointer from step 2b, and existing stories that need revising. Do not merge two commands into one story; if the cut needs more than 4 scenarios, split it. Finished stories get `status: review` and are run through the spec linter.
107
110
 
108
111
  ## 6. Review
109
- Read `.claude/skills/review-stories/SKILL.md` and follow it with the story IDs from step 5 as the arguments (only this feature's stories, not everything in `review`). The user still approves every change and every `ready`.
112
+ Read `.claude/skills/review-stories/SKILL.md` and follow it with the story IDs from step 5 as the arguments (only this feature's stories, not everything in `review`). The spec linter must be green before a story reaches `ready-for-human-review`; the user approves every change and every `ready`. There is no separate review subagent.
110
113
 
111
114
  ## 7. Wrap-up
112
- Summarize: the source and the route taken (idea, ticket, existing story or bug), glossary changes, new/changed events, ADRs proposed, a prototype run and its verdict (if any), stories created and their review outcome (`ready` vs. still open), open hotspots/questions. Point to `docs/stories/BACKLOG.md`, where `ready` stories are queued for the engineering workflow. For a bug, say which documented rule was restored, or that the rule changed and became a feature.
115
+ Summarize: the source and the route taken (idea, ticket, existing story or bug), glossary changes, new/changed events, ADRs proposed, research files created or refreshed and the findings the user adopted or rejected, a prototype run and its verdict (if any), stories created and their review outcome (`ready` vs. still open), open hotspots/questions. Point to `docs/stories/BACKLOG.md`, where `ready` stories are queued for the engineering workflow. For a bug, say which documented rule was restored, or that the rule changed and became a feature.
@@ -94,7 +94,7 @@ function storyRef(story: d.Story): StoryRef {
94
94
  path: d.rel(story.path),
95
95
  title: String(story.meta.title ?? ""),
96
96
  status: String(story.meta.status ?? ""),
97
- type: String(story.meta.type ?? "story"),
97
+ type: String(story.meta.type ?? "domain"),
98
98
  };
99
99
  }
100
100
 
@@ -27,4 +27,19 @@ Each round the user answers reshapes the tree: settled decisions push the fronti
27
27
 
28
28
  Finding _facts_ is your job, never the user's. When a frontier question needs a fact from the environment (filesystem, tools, etc.), dispatch a sub-agent to find it; don't ask the user for anything you could look up yourself. Don't block on it: a running exploration is an unsettled prerequisite, so only the questions downstream of it wait for the sub-agent to report; ask the rest of the frontier now. The _decisions_ are the user's: put each to them and wait.
29
29
 
30
+ ## Research before a round
31
+
32
+ When a frontier question depends on an external fact – authentication/identity, security, payment, privacy/data
33
+ protection, accessibility, performance, a new library or technology – load the `research` skill before the round. A
34
+ trigger is **not a mandate**: if `CONTEXT.md`, `docs/domain/events.yaml`, an accepted ADR, the UX guidelines, the
35
+ conventions or a valid research file already answers it, run nothing. One run per topic, not per story.
36
+
37
+ - The recommendation cites the finding and its source: `➡️ … (RFC 9700 §2.1.1; F1 in docs/research/oauth-pkce.md)`.
38
+ - Only a confirmed recommendation becomes a Gherkin scenario or checklist item with an observable threshold – never
39
+ "follow best practices". A finding that cannot be tested is context or a guideline, not an acceptance criterion.
40
+ - Rejected options are recorded with the reason in the story's `## Context` / `## Out of Scope` (or the ADR /
41
+ initiative). The research file stays evidence and is not rewritten into a decision log.
42
+ - A finding that contradicts `CONTEXT.md`, `events.yaml`, an accepted ADR or the UX guidelines is a grilling
43
+ question. Never edit the model to match the source silently.
44
+
30
45
  The session is done when the frontier is empty: every branch of the design tree visited, nothing left silently assumed. Do not act on it until the user confirms you have reached a shared understanding.
@@ -15,7 +15,8 @@ every done story, every ADR and every answered open question since then may have
15
15
  or differently important. Nothing here is a formality – a grooming run that changes nothing was a wasted run or a
16
16
  healthy backlog, and you have to be able to say which.
17
17
 
18
- Do **not** fix anything yourself. Grooming produces a decision for the user and a task for the `requirements-engineer`.
18
+ Do **not** fix anything yourself. Grooming produces a decision for the user. The main session carries the product and
19
+ engineering lenses; it does not delegate them to simulated roles.
19
20
 
20
21
  ## 1. Mechanical health check
21
22
 
@@ -39,22 +40,23 @@ rows in `OPEN_QUESTIONS.md`, and the "revisit when …" lines parked in `docs/re
39
40
  this list to the subagents – they cannot see it, and without it they re-read the same stories that were already
40
41
  reviewed once.
41
42
 
42
- ## 3. Challenge in parallel
43
+ ## 3. Challenge – two lenses, one pass
43
44
 
44
- Start in **one** message, with the full file paths, the scope and the change list from step 2:
45
+ The main session holds both lenses at once. Write down which one produced each finding; do not average a conflict
46
+ between them away.
45
47
 
46
- - `product-owner` – is the value still real and still in the vision? Is the story already covered by what was
47
- built? Does the MVP slice still hold? Which `must` is not a `must` any more, and which `could` turned out to be
48
- one? Which need from the vision still has no story?
49
- - `lead-dev` – do `depends_on`, `size` and `risk` still fit **now that the code exists**? Which story has become
48
+ - **Value** – is the value still real and still in the vision? Is the story already covered by what was built? Does
49
+ the MVP slice still hold? Which `must` is not a `must` any more, and which `could` turned out to be one? Which
50
+ need from the vision still has no story?
51
+ - **Build** – do `depends_on`, `size` and `risk` still fit **now that the code exists**? Which story has become
50
52
  smaller because the foundation is there, which bigger? Which dependency is technical fiction? Which story should
51
- be split, merged or dropped?
52
- - `ux-designer` – only for stories with the label `ui` (or an obvious frontend part): does the story still match
53
- `docs/product/ux-guidelines.md`, which one builds a screen that a newer story has replaced, and is there an open
54
- UX question that needs a prototype (the `prototype` skill) before the story can be reviewed again?
53
+ be split (one command!), re-typed as `chore`/`task`, or dropped?
55
54
 
56
- Tell each one explicitly: **recommend, don't rewrite** – they change only the frontmatter fields they own
57
- (`priority` for the PO, `size`/`risk`/`depends_on` for the lead dev), everything else comes back as a proposal.
55
+ For stories with `ui: true` (or an obvious frontend part), ask the `ux-designer` only when a concrete question needs
56
+ it – component/pattern, an open UX decision, or a prototype. It advises; it does not gate.
57
+
58
+ Do not hand the backlog to subagents: the change list from step 2 is context they cannot see, and re-reading stories
59
+ that were already reviewed once is the cost this workflow removes.
58
60
 
59
61
  ## 4. Consolidate
60
62
 
@@ -62,22 +64,22 @@ Write `docs/reviews/YYYY-MM-DD-backlog-grooming.md`:
62
64
 
63
65
  - the health-check findings with what they turned out to mean
64
66
  - per challenged story: keep / revise / split / merge / drop, with the reason and who said it
65
- - conflicts between the three – name them, don't average them away
67
+ - conflicts between the two lenses – name them, don't average them away
66
68
  - proposed new stories, and stories proposed for `priority: wont`
67
69
  - what explicitly stays as it is, so the next run does not re-litigate it
68
70
 
69
71
  ## 5. The user decides
70
72
 
71
73
  Present it in rounds, at most 3 questions at a time, each with a recommended answer. Adopt nothing without consent.
72
- A disagreement between PO and lead-dev is a question for the user, not something to resolve on their behalf.
74
+ A disagreement between value and build is a question for the user, not something to resolve on their behalf.
73
75
 
74
76
  ## 6. Apply
75
77
 
76
- - Content changes → `requirements-engineer`, referencing the grooming file.
78
+ - Content changes → edit the story in the main session, referencing the grooming file; then re-run the spec linter.
77
79
  - **Dropped stories are never deleted**: they get `priority: wont` and keep their file, so the decision stays
78
80
  traceable. A story that is wrong rather than unwanted goes back to `status: review` and through `/review-stories`.
79
81
  - A `done` story is never reopened – a change to finished behaviour is a new story.
80
- - New stories from the grooming get `status: draft` and go through `/review-stories` like any other.
82
+ - New stories from the grooming get `status: draft` and go through `/review-stories` like any other (linter → human).
81
83
  - With a tracker, push the applied changes (`/backlog-sync push`) before the wrap-up, so Jira/GitHub and the mirror
82
84
  agree. A story that is not linked yet stays a local draft until the push creates it.
83
85