methodology-m 0.3.1

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 (38) hide show
  1. package/bin/m.mjs +76 -0
  2. package/dist-m/CHANGELOG.md +45 -0
  3. package/dist-m/capabilities/bootstrap-root-repo/SKILL.md +138 -0
  4. package/dist-m/capabilities/decompose-story/SKILL.md +299 -0
  5. package/dist-m/capabilities/generate-acceptance-tests/SKILL.md +305 -0
  6. package/dist-m/capabilities/generate-pats/SKILL.md +131 -0
  7. package/dist-m/capabilities/scaffold-repo/SKILL.md +641 -0
  8. package/dist-m/capabilities/setup-workspace/SKILL.md +70 -0
  9. package/dist-m/capabilities/tag-release/SKILL.md +121 -0
  10. package/dist-m/capabilities/wire-orchestration/SKILL.md +351 -0
  11. package/dist-m/m.md +126 -0
  12. package/dist-m/providers/provider-interface.md +191 -0
  13. package/dist-m/providers/scm/gitlab.md +377 -0
  14. package/dist-m/schemas/pat.schema.json +161 -0
  15. package/dist-m/schemas/project.schema.json +177 -0
  16. package/package.json +27 -0
  17. package/src/commands/changelog.mjs +58 -0
  18. package/src/commands/clone.mjs +199 -0
  19. package/src/commands/diff.mjs +29 -0
  20. package/src/commands/init.mjs +51 -0
  21. package/src/commands/update.mjs +41 -0
  22. package/src/commands/version.mjs +43 -0
  23. package/src/lib/copy.mjs +20 -0
  24. package/src/lib/detect-agent.mjs +25 -0
  25. package/src/lib/diff-trees.mjs +95 -0
  26. package/src/lib/topology.mjs +62 -0
  27. package/src/lib/version-file.mjs +25 -0
  28. package/src/lib/workspace.mjs +40 -0
  29. package/src/lib/wrappers/claude.mjs +54 -0
  30. package/templates/claude/skills/bootstrap-root-repo/SKILL.md +13 -0
  31. package/templates/claude/skills/decompose-story/SKILL.md +13 -0
  32. package/templates/claude/skills/generate-acceptance-tests/SKILL.md +13 -0
  33. package/templates/claude/skills/generate-pats/SKILL.md +13 -0
  34. package/templates/claude/skills/scaffold-repo/SKILL.md +13 -0
  35. package/templates/claude/skills/setup-workspace/SKILL.md +13 -0
  36. package/templates/claude/skills/tag-release/SKILL.md +13 -0
  37. package/templates/claude/skills/wire-orchestration/SKILL.md +13 -0
  38. package/templates/claude/steering/m-steering.md +3 -0
@@ -0,0 +1,305 @@
1
+ # generate-acceptance-tests
2
+
3
+ **Capability:** Transform PAT stubs into executable acceptance test code
4
+
5
+ ## What it does
6
+
7
+ Reads the PAT stub file (`pats/<sub-task-id>.stub.js`) and the sub-task
8
+ file, then generates real, executable acceptance tests (CATs) using the
9
+ appropriate framework for the component type. After this step, `npm test`
10
+ proves the implementation meets its contract.
11
+
12
+ The stub is the specification. The spec is the compiled proof. This
13
+ capability bridges the two.
14
+
15
+ **Scope:** This capability produces CATs — compiled acceptance tests that
16
+ prove the PAT contract is met. Unit tests (vitest, Testing Library, etc.)
17
+ are a separate developer-level concern created during implementation, not
18
+ by this capability. Both layers coexist in the repo but serve different
19
+ purposes and are authored at different times.
20
+
21
+ ## Parameters
22
+
23
+ | Parameter | Type | Required | Description |
24
+ |---------------|--------|----------|----------------------------------------------------|
25
+ | sub-task-id | string | Yes | Sub-task identifier (e.g. TODOM-000c) |
26
+ | repo-path | path | No | Local path to the managed repo (inferred from CWD if omitted) |
27
+
28
+ ## Prerequisites
29
+
30
+ - Managed repo is scaffolded (`scaffold-repo`)
31
+ - Implementation exists (`implement-component` has been run)
32
+ - PAT stub exists at `pats/<sub-task-id>.stub.js`
33
+ - Sub-task file exists at `jira/<sub-task-id>.md`
34
+
35
+ ## Execution
36
+
37
+ ### Step 1 — Read the contract and implementation
38
+
39
+ Read `pats/<sub-task-id>.stub.js` — this is the test specification
40
+ in pseudocode form. Each `it()` block contains comments describing
41
+ what to assert.
42
+
43
+ Read `jira/<sub-task-id>.md` — for acceptance criteria context and
44
+ component role.
45
+
46
+ Read the implementation source files (`src/`) — to understand the
47
+ API surface, exports, and how to import the component under test.
48
+
49
+ ### Step 2 — Determine test framework
50
+
51
+ Based on the component role:
52
+
53
+ | Role | CAT Framework | Test Runner | Why |
54
+ |------|--------------|-------------|-----|
55
+ | backend (API) | supertest | vitest | HTTP contract testing without starting a server |
56
+ | frontend (MFE) | Cypress | cypress | PATs are user-level criteria — must validate through the real UI in a browser |
57
+ | frontend-host (shell) | Cypress | cypress | Story-level, composed system, browser required |
58
+
59
+ **Why Cypress for MFEs?** PATs are acceptance criteria written from the
60
+ user's perspective. For any UI component, that means verifying behaviour
61
+ through the rendered UI in a real browser — not through jsdom unit tests.
62
+ Unit tests (vitest + Testing Library) are valuable during implementation
63
+ for fast feedback on component logic, but they are NOT PAT compilations.
64
+ Only browser-based tests satisfy the PAT contract for frontend components.
65
+
66
+ ### Step 3 — Add test dependencies
67
+
68
+ Add the required devDependencies to `package.json`:
69
+
70
+ **For backend API repos:**
71
+ - `vitest` — test runner
72
+ - `supertest` — HTTP assertion library
73
+
74
+ **For frontend repos (MFE, shell):**
75
+ - `cypress` — browser-based acceptance testing
76
+
77
+ Also add runtime helpers needed by the Cypress test job:
78
+ - `express` — for API stubs (if not already present)
79
+ - `cors` — for API stubs (if not already present)
80
+ - `serve` — static file server for the built frontend
81
+ - `wait-on` — wait for services to be ready before running tests
82
+
83
+ ### Step 4 — Create test config
84
+
85
+ **For backend API repos:** If the repo doesn't already have a
86
+ `vitest.config.js`, create one:
87
+
88
+ ```
89
+ import { defineConfig } from 'vitest/config'
90
+
91
+ export default defineConfig({
92
+ test: {
93
+ globals: true,
94
+ },
95
+ })
96
+ ```
97
+
98
+ **For frontend repos (MFE, shell):** If the repo doesn't already have a
99
+ `cypress.config.js`, create one:
100
+
101
+ ```
102
+ const { defineConfig } = require('cypress')
103
+
104
+ module.exports = defineConfig({
105
+ e2e: {
106
+ baseUrl: 'http://localhost:3001',
107
+ supportFile: false,
108
+ specPattern: 'pats/**/*.cy.js',
109
+ },
110
+ })
111
+ ```
112
+
113
+ The `baseUrl` should match the port the built frontend is served on.
114
+ The `specPattern` points to the PAT directory where CATs live.
115
+
116
+ ### Step 5 — Transform stubs into specs
117
+
118
+ Create `pats/<sub-task-id>.spec.js` (backend) or
119
+ `pats/<sub-task-id>.cy.js` (frontend) alongside the stub file.
120
+
121
+ **Transformation rules:**
122
+ - Keep the same `describe()` and `it()` structure from the stub
123
+ - Replace comment placeholders with real assertions
124
+ - Import the component under test (app, component, etc.)
125
+ - For API tests: use supertest to make HTTP requests against the
126
+ imported app (not a running server)
127
+ - For frontend tests (MFE, shell): use Cypress to visit the page,
128
+ interact with elements via `data-testid` attributes, and assert
129
+ on visible UI state
130
+
131
+ ### Step 5a — Handle PAT supersession (replaces/removes)
132
+
133
+ Before writing the new spec, check the sub-task file for `replaces`
134
+ or `removes` declarations in the acceptance criteria.
135
+
136
+ **For `replaces`:** Find the existing test file for the superseded AC
137
+ (e.g. `pats/TODOM-000b.cy.js` if replacing `TODOM-000b/AC-001`).
138
+ Update or rewrite the affected test(s) in that file to match the new
139
+ behaviour. Do NOT leave old assertions that test superseded behaviour
140
+ — they will fail in CI.
141
+
142
+ **For `removes`:** Find the existing test file and delete the test(s)
143
+ for the removed AC. If the entire file becomes empty, delete the file.
144
+
145
+ **This is not optional.** If the sub-task declares supersession and
146
+ you skip this step, old tests will fail in CI. The test suite must
147
+ always reflect the current active PAT set — not the historical one.
148
+
149
+ **For backend API repos (supertest pattern):**
150
+ ```
151
+ import request from 'supertest'
152
+ import app from '../src/app.js'
153
+
154
+ describe('...', () => {
155
+ it('...', async () => {
156
+ const res = await request(app).get('/endpoint')
157
+ expect(res.status).toBe(200)
158
+ expect(res.body).toHaveProperty('expectedField')
159
+ })
160
+ })
161
+ ```
162
+
163
+ **Key:** Import `app.js` directly, not `server.js`. Supertest
164
+ binds to the app internally — no port needed, no server to clean up.
165
+
166
+ **For frontend repos (Cypress pattern):**
167
+ ```
168
+ describe('<sub-task-id>: <description>', () => {
169
+ beforeEach(() => {
170
+ cy.visit('/')
171
+ })
172
+
173
+ it('<acceptance criterion>', () => {
174
+ cy.get('[data-testid="<element>"]').should('be.visible')
175
+ // ... assertions matching the PAT stub
176
+ })
177
+ })
178
+ ```
179
+
180
+ **Key:** Cypress tests run against the built frontend served statically.
181
+ API stubs provide the backend. The test validates the full user-facing
182
+ behaviour described in the PAT.
183
+
184
+ ### Step 6 — Update test script and CI pipeline
185
+
186
+ **For backend API repos:**
187
+
188
+ Ensure `package.json` has:
189
+ ```
190
+ "test": "vitest run"
191
+ ```
192
+
193
+ The `run` flag ensures vitest executes once and exits (no watch mode).
194
+ This is critical for CI — watch mode would hang the pipeline.
195
+
196
+ **For frontend repos (MFE, shell):**
197
+
198
+ Ensure `package.json` has:
199
+ ```
200
+ "test": "cypress run"
201
+ ```
202
+
203
+ Then update `.gitlab-ci.yml` to handle the Cypress test job properly.
204
+ The test job needs a Cypress Docker image, stub startup, a static
205
+ server for the built frontend, and health checks before running tests.
206
+
207
+ **CI image pinning rule:** The `cypress/included` image tag MUST match
208
+ the Cypress version in `package.json`. Read the Cypress version from
209
+ `devDependencies` and use that exact version as the image tag. Never
210
+ use `:latest` — it drifts independently of the npm package and causes
211
+ "binary not found" failures when the versions diverge.
212
+
213
+ Updated test job for frontend repos:
214
+
215
+ ```
216
+ test:
217
+ stage: test
218
+ image:
219
+ name: cypress/included:<cypress-version-from-package.json>
220
+ entrypoint: [""]
221
+ script:
222
+ - node pats/stubs/api-read.js &
223
+ - node pats/stubs/api-write.js &
224
+ - npm run build --if-present
225
+ - npx serve dist -l 3001 &
226
+ - npx wait-on http://localhost:3002/health http://localhost:3003/health http://localhost:3001
227
+ - npx cypress run
228
+ needs: [install]
229
+ ```
230
+
231
+ **Stub startup:** Start all API stubs in `pats/stubs/api-*.js` as
232
+ background processes. Each stub exposes a `/health` endpoint.
233
+
234
+ **Build and serve:** Build the frontend, then serve the `dist/` folder
235
+ on the component's port (e.g. 3001 for MFE).
236
+
237
+ **Wait-on:** Wait for all stub health endpoints and the static server
238
+ before running Cypress. Without this, tests hit connection refused.
239
+
240
+ **Image entrypoint:** The `cypress/included` image has a default
241
+ entrypoint that runs `cypress run` immediately. Setting
242
+ `entrypoint: [""]` overrides this so the CI script controls execution.
243
+
244
+ ### Step 7 — Install dependencies and run tests
245
+
246
+ Run `npm install` to install the new devDependencies and update
247
+ `package-lock.json`.
248
+
249
+ Run `npm test` to verify the generated tests pass against the
250
+ implementation.
251
+
252
+ **If tests fail:** Review the spec, fix the assertions or the
253
+ implementation, and re-run. The goal is green tests before moving on.
254
+
255
+ ### Step 8 — Present for review
256
+
257
+ Show the user:
258
+ - The stub file (what was specified)
259
+ - The spec file (what was generated)
260
+ - The test output (passing/failing)
261
+
262
+ Ask the user to review and confirm. They may want to adjust
263
+ assertions, add edge cases, or rename test descriptions.
264
+
265
+ ### Step 9 — Report
266
+
267
+ Output:
268
+ - Spec file created (`pats/<sub-task-id>.spec.js` or `pats/<sub-task-id>.cy.js`)
269
+ - Test framework and dependencies added
270
+ - CI pipeline updated (for frontend repos: pinned Cypress image, stub startup)
271
+ - Test results (pass/fail count)
272
+ - Reminder: do NOT delete the stub file — it's the human-readable
273
+ contract. The spec is the machine-readable proof. Both live in `pats/`.
274
+
275
+ ## Notes
276
+
277
+ - The stub file is never deleted or modified. It remains as the
278
+ human-readable specification alongside the executable spec.
279
+ - Tests must import the app/component directly, not via a running
280
+ server. This is why `implement-component` separates app from server.
281
+ - For API repos, supertest + vitest is the standard. Supertest handles
282
+ the HTTP layer; vitest provides the test runner and assertions.
283
+ - For frontend repos (MFE, shell), Cypress is the CAT framework.
284
+ It validates the real UI in a real browser — the only way to prove
285
+ user-facing acceptance criteria are met.
286
+ - **Unit tests vs CATs:** Frontend repos will typically have BOTH
287
+ vitest unit tests (created during implementation for fast feedback)
288
+ and Cypress CATs (created by this capability to prove the PAT
289
+ contract). They coexist. Unit tests run via `npm run test:unit`,
290
+ CATs run via `npm test` (which maps to `cypress run`). CI runs
291
+ `npm test` — the CATs are what gate the MR.
292
+ - The `vitest run` flag is essential for backend repos. Without it,
293
+ vitest starts in watch mode, which hangs CI pipelines indefinitely.
294
+ - PAT stubs use `describe`/`it` syntax even though they're pseudocode.
295
+ This makes the transformation mechanical — same structure, real
296
+ assertions replacing comments.
297
+ - **CI image pinning:** Always pin `cypress/included` to the exact
298
+ version from `package.json`. The `:latest` tag drifts independently
299
+ of the npm package — when they diverge, the Cypress binary path
300
+ doesn't match and CI fails with "binary not found." This is a
301
+ silent, intermittent failure that's hard to debug in a live demo.
302
+ - **Stub/CI coupling:** Every stub in `pats/stubs/api-*.js` must be
303
+ started in the CI test job and its `/health` endpoint must be in
304
+ the `wait-on` list. If you add or modify a stub, update the CI
305
+ config to match.
@@ -0,0 +1,131 @@
1
+ # generate-pats
2
+
3
+ **Capability:** Generate story-level PATs from a story file
4
+
5
+ ## What it does
6
+
7
+ Reads a story file, generates a `pat.yaml` file following the PAT.yaml schema
8
+ defined in Methodology M. The PAT file is the machine-readable, structured
9
+ expression of the story's acceptance criteria — the source of truth that drives
10
+ decomposition, implementation, and validation.
11
+
12
+ Story-level PATs are topology-agnostic. They describe user outcomes, not
13
+ component behaviour. No technical implementation details, no component names.
14
+
15
+ ## Parameters
16
+
17
+ | Parameter | Type | Required | Description |
18
+ |-----------|------|----------|-------------|
19
+ | `story-file` | path | Yes | Path to the source story markdown file |
20
+ | `workspace` | path | No | Output folder for generated artefacts |
21
+
22
+ ## Execution
23
+
24
+ ### Step 1 — Read the story
25
+
26
+ Read the story file. Extract:
27
+ - Story ID
28
+ - Acceptance criteria (from the story's AC section)
29
+
30
+ ### Step 2 — Generate PAT draft
31
+
32
+ Transform each acceptance criterion into a PAT entry following the schema:
33
+
34
+ ```
35
+ story: <story-id>
36
+ version: 1
37
+
38
+ acceptance:
39
+ - id: AC-001
40
+ when: <user action or state>
41
+ then: <expected outcome>
42
+ steps:
43
+ - navigate: <path>
44
+ - assert: "[data-testid='<id>']" <check>
45
+ ...
46
+ ```
47
+
48
+ Rules for generation:
49
+ - `when`/`then` are plain English, topology-agnostic
50
+ - `steps` are ordered and deterministic, suitable for direct test translation
51
+ - All interactive elements use `data-testid` attributes for stable selectors
52
+ - Each AC gets a unique `id` within the story (AC-001, AC-002, etc.)
53
+ - No component names, no API paths, no technical details in `when`/`then`
54
+ - `steps` may reference technical details (URLs, selectors) as these are
55
+ the concrete validation mechanism
56
+
57
+ ### Step 2a — Detect PAT conflicts with existing stories
58
+
59
+ Before finalising the PAT draft, scan existing PAT files in the workspace
60
+ (or root repo `pats/` folder) for conflicts with the new story's ACs.
61
+
62
+ A conflict exists when:
63
+ - A new AC changes behaviour that an existing AC asserts (e.g. "renders
64
+ Hello" → "renders Todo list")
65
+ - A new AC removes a feature that an existing AC validates
66
+ - A new AC changes the UI structure that existing ACs depend on (e.g.
67
+ different data-testid attributes, different page layout)
68
+
69
+ For each conflict, add a `replaces` or `removes` declaration to the
70
+ new AC:
71
+
72
+ ```
73
+ - id: AC-001
74
+ when: user opens the app
75
+ then: todo list is displayed with item count
76
+ replaces: TODOM-000/AC-001 # was: MFE renders Hello component
77
+ steps:
78
+ ...
79
+ ```
80
+
81
+ - `replaces: <story-id>/AC-<id>` — the new AC supersedes the old one.
82
+ The old AC's compiled test should be updated or replaced.
83
+ - `removes: <story-id>/AC-<id>` — the old AC is no longer valid and
84
+ its compiled test should be deleted.
85
+
86
+ **This step is critical for test suite integrity.** Without it, old
87
+ compiled tests (CATs) will fail when new stories change behaviour,
88
+ causing CI failures that look like bugs but are actually stale tests.
89
+
90
+ ### Step 3 — Present for review
91
+
92
+ Show the generated PAT to the user. Wait for confirmation or changes.
93
+
94
+ The PAT is a critical artefact — it drives everything downstream. The user
95
+ must review and approve before it's written.
96
+
97
+ ### Step 4 — Write to workspace
98
+
99
+ On confirmation, write `<story-id>.pat.yaml` to the workspace folder.
100
+
101
+ ## PAT.yaml schema
102
+
103
+ ```
104
+ story: <story-id>
105
+ version: 1
106
+
107
+ acceptance:
108
+ - id: <unique-id>
109
+ when: <trigger condition>
110
+ then: <expected outcome>
111
+ steps:
112
+ - navigate: <path>
113
+ - click: "[data-testid='<id>']"
114
+ - type: "[data-testid='<id>']" value "<text>"
115
+ - assert: "[data-testid='<id>']" is visible
116
+ - assert: "[data-testid='<id>']" contains "<value>"
117
+ - assert: "[data-testid='<id>']" count > 0
118
+ - wait: "[data-testid='<id>']" is visible
119
+ replaces: <old-ac-id> # optional
120
+ removes: <old-ac-id> # optional
121
+ ```
122
+
123
+ ## Notes
124
+
125
+ - Story-level PATs are topology-agnostic — pure user outcomes
126
+ - The PAT file is the input to `decompose-story`, not the story prose
127
+ - PATs live in the root repo under `pats/` in a real project; in the
128
+ workshop they land in the workspace folder
129
+ - `replaces` and `removes` are used when stories modify existing behaviour
130
+ - The `version` field is the schema version (always 1 for now), not the
131
+ story version