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
package/bin/m.mjs ADDED
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Copyright (C) 2026 Textology Labs Ltd. All rights reserved.
4
+
5
+ const command = process.argv[2];
6
+ const args = process.argv.slice(3);
7
+
8
+ const HELP = `
9
+ methodology-m — inject and manage Methodology M in your project
10
+
11
+ Usage:
12
+ m init Set up M in the current project (root repo)
13
+ m clone <url> [--ide X] Clone root + all managed repos into a workspace
14
+ m clone [--ide X] (from inside root repo) Clone missing siblings
15
+ m update [version] Upgrade M to a new version
16
+ m diff Show changes between installed and available M
17
+ m version Show installed, bundled, and latest versions
18
+ m changelog [version] Show changelog (optionally for a specific version)
19
+ m help Show this help
20
+
21
+ Starting a new M project? Run "m init" in your root repo.
22
+ Joining an existing project? Run "m clone <root-repo-url>".
23
+
24
+ Options:
25
+ --ide vscode IDE workspace format (default: vscode)
26
+ `;
27
+
28
+ async function main() {
29
+ switch (command) {
30
+ case 'init': {
31
+ const { init } = await import('../src/commands/init.mjs');
32
+ await init(args);
33
+ break;
34
+ }
35
+ case 'clone': {
36
+ const { clone } = await import('../src/commands/clone.mjs');
37
+ await clone(args);
38
+ break;
39
+ }
40
+ case 'update': {
41
+ const { update } = await import('../src/commands/update.mjs');
42
+ await update(args);
43
+ break;
44
+ }
45
+ case 'diff': {
46
+ const { diff } = await import('../src/commands/diff.mjs');
47
+ await diff(args);
48
+ break;
49
+ }
50
+ case 'version': {
51
+ const { version } = await import('../src/commands/version.mjs');
52
+ await version(args);
53
+ break;
54
+ }
55
+ case 'changelog': {
56
+ const { changelog } = await import('../src/commands/changelog.mjs');
57
+ await changelog(args);
58
+ break;
59
+ }
60
+ case 'help':
61
+ case '--help':
62
+ case '-h':
63
+ case undefined:
64
+ console.log(HELP);
65
+ break;
66
+ default:
67
+ console.error(`Unknown command: ${command}`);
68
+ console.log(HELP);
69
+ process.exit(1);
70
+ }
71
+ }
72
+
73
+ main().catch((err) => {
74
+ console.error(err.message);
75
+ process.exit(1);
76
+ });
@@ -0,0 +1,45 @@
1
+ # Changelog
2
+
3
+ All notable changes to Methodology M are documented in this file.
4
+
5
+ ## [0.3.1] — 2026-04-11
6
+
7
+ ### Added
8
+ - **M CLI** (`methodology-m` npm package) — zero-dependency Node.js CLI for distributing M into projects. Commands: `init`, `clone`, `update`, `diff`, `version`, `changelog`.
9
+ - **`m clone`** — clones root repo + all managed repos from `project.yaml` topology, generates IDE workspace file (VS Code by default, configurable via `--ide`).
10
+ - **JSON Schemas** — formal contracts at `.m/schemas/pat.schema.json` (PAT.yaml) and `.m/schemas/project.schema.json` (project.yaml). Agent rule in `m.md` requires validation against schemas before committing generated artefacts.
11
+ - **Backlog prioritisation** — all 41 improvement items tiered by impact (Tier 1: structural integrity, Tier 2: delivery loop, Tier 3: extensibility, Tier 4: polish). TOC added to `docs/improvements-and-ideas.md`.
12
+ - **I-041** improvement item — pessimistic invalidation (push `pending` to all story MRs when any constituent pipeline starts).
13
+
14
+ ### Changed
15
+ - **Agent Skills standard** — all capabilities migrated from `.m/capabilities/<name>.md` to `.m/capabilities/<name>/SKILL.md` per the [agentskills.io](https://agentskills.io) standard. Claude wrappers migrated from one monolithic skill to 8 individual skills in `.claude/skills/<name>/SKILL.md`.
16
+ - **README.md** — rewritten to reflect current state: `.m/` layer, CLI, capabilities, provider model.
17
+ - **`.m/m.md`** — schemas added to Key Files and Directory Structure. "Schemas — Mandatory Validation" section with agent enforcement rule. Removed empty `steering/`, `roles/` from directory listing.
18
+
19
+ ## [0.3.0] — 2026-04-11
20
+
21
+ ### Added
22
+ - **Agent-neutral `.m/` layer** — capabilities, steering, and provider interface extracted from Kiro powers into a canonical, agent-agnostic directory. Any AI agent can execute M capabilities by reading `.m/`.
23
+ - **Provider interface** — formal `scm.*` namespace with 14 function contracts (`create_repo`, `protect_branch`, `create_webhook`, etc.). Provider resolution via `project.yaml` → `.m/providers/<category>/<provider>.md`.
24
+ - **GitLab SCM provider** — reference implementation at `.m/providers/scm/gitlab.md` mapping all `scm.*` functions to GitLab MCP tools with full gotcha documentation.
25
+ - **Claude adapter** — thin wrapper skill (`.claude/skills/m-capabilities/SKILL.md`) and steering (`.claude/steering/m-steering.md`) pointing to canonical `.m/` content.
26
+ - **`decompose-story` Step 4** — auto-compile story PAT into Cypress spec and raise root MR at decomposition time (I-039). Integration gate exists from the moment a story is decomposed.
27
+ - **`scm.create_branch`** and **`scm.create_merge_request`** functions added to provider interface.
28
+ - **Pipeline failure propagation (I-032)** — managed repo webhooks now include `pipeline_events: true`. `detect-trigger-event.sh` handles `pipeline_failure` event type, skipping compose and going straight to failure fan-out.
29
+ - **Completeness failure mode** — integrity gate now checks ALL repos (managed + root) for open story MRs.
30
+ - **I-040** improvement item — topology changes (adding/removing components in a live project).
31
+
32
+ ### Changed
33
+ - **`wire-orchestration` capability** — updated with pipeline events on webhooks, `pipeline_failure` detection, fan-out to all repos including root, and inline `after_script` pattern for validate:integration status reporting.
34
+ - **`report-shadow-status.sh`** — `REPOS` includes root repo alongside managed repos.
35
+ - **`integration-test.sh`** — `REPOS` replaces `MANAGED_REPOS`, includes root repo.
36
+ - **Path convention** — all paths in M documents are relative to repo root (pinned in `.m/m.md`).
37
+
38
+ ### Fixed
39
+ - Root repo MR missing from story integrity gate (I-039 partial).
40
+ - Cypress image pinning (`cypress/included:latest` → `cypress/included:15.13.0`) on MFE repo.
41
+ - `validate:integration` CI pipeline failure caused by `when: on_failure` inside `rules:` block — replaced with inline `after_script` fan-out pattern.
42
+
43
+ ## [0.2.0] — 2026-04-07
44
+
45
+ Initial M Power capabilities under `.kiro/powers/m-power/`. Workshop reference implementation with GitLab CI orchestration.
@@ -0,0 +1,138 @@
1
+ # bootstrap-root-repo
2
+
3
+ **Capability:** Create and seed the root repo for an M-type project
4
+
5
+ ## What it does
6
+
7
+ Creates the root repo on GitLab, seeds it with the project manifest and
8
+ Story Zero. After this step, the root repo is the source of truth — all
9
+ subsequent M Power actions read from and write to it.
10
+
11
+ On completion, offers to run `generate-pats` to produce story-level PATs
12
+ and commit them to the root repo. PAT generation is delegated to the
13
+ existing `generate-pats` capability — this capability orchestrates the
14
+ sequence but does not reimplement PAT logic.
15
+
16
+ ## Parameters
17
+
18
+ | Parameter | Type | Required | Description |
19
+ |------------------|--------|----------|------------------------------------------------|
20
+ | story-file | path | Yes | Path to Story Zero markdown file |
21
+ | group-path | string | No | GitLab group path (extracted from story if omitted) |
22
+ | project-name | string | No | Project name (extracted from story if omitted) |
23
+ | components | list | No | Component catalogue (extracted from story if omitted) |
24
+ | topology-mode | string | No | "distributed" or "monolith-first" (default: distributed) |
25
+ | pat-framework | string | No | "cypress" or "playwright" (default: cypress) |
26
+ | deployment-model | string | No | "docker-compose", "kubernetes", or "none" |
27
+
28
+ Story Zero is the primary input. If the story file contains a `## Project`
29
+ section, the capability extracts project metadata automatically. Explicit
30
+ parameters override extracted values. Anything the capability cannot find
31
+ in the story or in explicit parameters, it asks the user for.
32
+
33
+ ### Expected `## Project` section format
34
+
35
+ The story file's `## Project` section should contain:
36
+
37
+ - `Name:` — project name (used for repo naming pattern)
38
+ - `GitLab group:` — full group path where repos will be created
39
+ - `Topology:` — "distributed" or "monolith-first"
40
+ - `CI platform:` — "GitLab CI", "GitHub Actions", or "none"
41
+ - `Story management:` — "local markdown" or "Jira"
42
+ - `PAT framework:` — "Cypress", "Playwright", or "both"
43
+ - `Deployment:` — "Docker Compose", "Kubernetes", or "none"
44
+ - Component list — repo names with roles and types (embedded/referenced)
45
+
46
+ ## Execution
47
+
48
+ ### Step 1 — Extract project metadata
49
+
50
+ Read the story file. Parse the `## Project` section to extract:
51
+ - Project name (from `Name:` field)
52
+ - GitLab group path (from `GitLab group:` field)
53
+ - Component catalogue (from the repo list)
54
+
55
+ If any of these are missing from the story and not provided as explicit
56
+ parameters, ask the user.
57
+
58
+ ### Step 2 — Create the root repo
59
+
60
+ ```
61
+ scm.create_repo(
62
+ name: "<project-name>-root",
63
+ namespace_id: <resolved-from-group-path>,
64
+ initialize_readme: false
65
+ )
66
+ ```
67
+
68
+ Do NOT initialise with README — the seed commit in Step 6 includes a
69
+ project-specific README. Initialising with a default README causes a
70
+ conflict when pushing the seed files.
71
+
72
+ ### Step 3 — Generate project.yaml
73
+
74
+ Build the project manifest from the component catalogue:
75
+
76
+ - Shell component: embedded, location `./packages/shell`
77
+ - All other components: type based on topology-mode
78
+ - distributed: referenced, location `<group-path>/<project-name>-<component>`
79
+ - monolith-first: embedded, location `./packages/<component>`
80
+ - All tags set to `~` (YAML null — nothing released yet)
81
+
82
+ ### Step 4 — Seed Story Zero
83
+
84
+ Place the story file into the root repo at `jira/<story-id>.md`.
85
+
86
+ ### Step 5 — Create conventional folder structure
87
+
88
+ Create placeholder structure for the root repo:
89
+
90
+ - `pats/` — story-level PAT files (empty until generate-pats runs)
91
+ - `stories/` — readiness trackers
92
+ - `packages/shell/` — shell package stub (embedded component)
93
+ - `.m/` — methodology configuration (steering, capabilities)
94
+
95
+ ### Step 6 — Commit and push
96
+
97
+ Commit all seeded files to the root repo in a single commit:
98
+
99
+ - `project.yaml`
100
+ - `jira/<story-id>.md`
101
+ - `README.md` (project-specific, not the GitLab boilerplate)
102
+ - Folder structure with `.gitkeep` files
103
+
104
+ Because the repo was created without `initialize_with_readme`, all files
105
+ can be pushed in one commit with no conflicts.
106
+
107
+ ### Step 7 — Offer PAT generation
108
+
109
+ Present the user with:
110
+
111
+ ```
112
+ Root repo created and seeded with Story Zero.
113
+ Want me to generate PATs now? (delegates to generate-pats)
114
+ ```
115
+
116
+ If confirmed, run `generate-pats` with:
117
+ - `story-file`: the story file just committed to the root repo
118
+ - Output target: `pats/<story-id>.pat.yaml` in the root repo
119
+
120
+ The `generate-pats` capability handles the draft/review/confirm cycle.
121
+ On confirmation, the PAT file is committed to the root repo.
122
+
123
+ ### Step 8 — Report
124
+
125
+ Output the root repo URL and a summary of what was created.
126
+ Note that the next step is `decompose-story`.
127
+
128
+ ## Notes
129
+
130
+ - The root repo becomes the source of truth the moment it's created
131
+ - This capability orchestrates a sequence but delegates PAT generation
132
+ to `generate-pats` — each capability stays atomic
133
+ - Managed repos are NOT created here — that happens during
134
+ `decompose-story` or via a future `scaffold-repo` capability
135
+ - The story file parameter can be a local file path; the capability
136
+ reads it and commits it to the root repo
137
+ - The user has a decision point between seeding and PAT generation —
138
+ they can pause, edit the story, or generate PATs later
@@ -0,0 +1,299 @@
1
+ # decompose-story
2
+
3
+ **Capability:** Decompose a story into component-scoped sub-tasks
4
+
5
+ ## What it does
6
+
7
+ Reads a story file, proposes a mapping of story-level PATs to components,
8
+ waits for confirmation, then generates:
9
+
10
+ - An enriched story file in the workspace with the mapping and sub-task refs
11
+ - One sub-task file per component in the workspace
12
+
13
+ The source story file is never modified.
14
+
15
+ ## Parameters
16
+
17
+ | Parameter | Type | Required | Description |
18
+ |-----------|------|----------|-------------|
19
+ | `story-file` | path | Yes | Path to the source story markdown file |
20
+ | `pat-file` | path | Yes | Path to the story-level PAT.yaml file (generated by `generate-pats`) |
21
+ | `workspace` | path | No | Output folder for generated artefacts |
22
+
23
+ ## Execution
24
+
25
+ ### Step 1 — Read the story and PATs
26
+
27
+ Read the story file. Extract:
28
+ - Story ID and title
29
+ - Component list (from the Project section)
30
+
31
+ Read the PAT file. Extract:
32
+ - Story-level acceptance criteria (the `acceptance` entries)
33
+
34
+ ### Step 2 — Propose PAT mapping
35
+
36
+ Reason about which PATs (from the pat.yaml `acceptance` entries) each component
37
+ is responsible for, then present the proposed mapping to the user.
38
+
39
+ **PAT supersession:** If any PAT in the new story declares `replaces` or
40
+ `removes` against an existing PAT from a previous story, include this in
41
+ the mapping presentation:
42
+
43
+ ```
44
+ <component-name> (sub-task: <story-id>a)
45
+ - <PAT description>
46
+ - <PAT description> [replaces TODOM-000/AC-001]
47
+ ```
48
+
49
+ The sub-task file for that component must include the supersession info
50
+ in its acceptance criteria so the CAT compilation step knows which
51
+ existing tests to update or remove.
52
+
53
+ **Mandatory root repo sub-task:** Every story MUST include a sub-task for the
54
+ root repo, regardless of whether the shell code changes. The root repo owns
55
+ story-level integration tests — the gate that validates the composed system
56
+ satisfies the story's acceptance criteria. Without this sub-task, shadow
57
+ integration has no tests to run and will fail structurally.
58
+
59
+ The root repo sub-task always includes:
60
+ - Story-level integration tests (`scripts/integration-tests/<story-id>.sh`)
61
+ - Any compose config changes needed for the story (e.g. shared volumes, new services)
62
+ - Readiness tracker updates
63
+
64
+ Even when the shell component has no feature changes, the root repo sub-task
65
+ exists because the integration tests are the root repo's contribution to
66
+ every story. This is not optional — it is how M ensures that shadow
67
+ integration is a real gate, not a permissive placeholder.
68
+
69
+ Present the proposed mapping to the user:
70
+
71
+ ```
72
+ Proposed PAT mapping for <story-id>:
73
+
74
+ <component-name> (sub-task: <story-id>a)
75
+ - <PAT description>
76
+ - <PAT description>
77
+
78
+ <component-name> (sub-task: <story-id>b)
79
+ - <PAT description>
80
+
81
+ root (sub-task: <story-id><last-suffix>) [MANDATORY]
82
+ - Story-level integration tests
83
+ - Compose config changes (if any)
84
+ - End-to-end validation of all story PATs
85
+
86
+ ...
87
+
88
+ Confirm, or tell me what to change.
89
+ ```
90
+
91
+ Wait for explicit confirmation before writing any files.
92
+
93
+ ### Step 3 — Generate workspace artefacts
94
+
95
+ On confirmation, write to the workspace folder:
96
+
97
+ **Enriched story: `<story-id>.md`**
98
+
99
+ Copy of the source story with two additions:
100
+ - A `## Component PAT Mapping` section showing which PATs each component owns
101
+ - A `## Sub-Tasks` section listing the generated sub-task IDs and their repos
102
+
103
+ **Readiness tracker: `<story-id>.readiness.yaml`**
104
+
105
+ Tracks high-water marks for each component sub-task. All marks start as null.
106
+ This is the artefact that monitors story progress through the Development phase.
107
+ It gets committed to the root repo under `stories/<story-id>.yaml`.
108
+
109
+ ```
110
+ story: <story-id>
111
+ status: pending
112
+
113
+ components:
114
+ - name: <component-name>
115
+ subtask: <story-id><suffix>
116
+ high-water-mark: null
117
+ ...
118
+
119
+ story-pats:
120
+ - pats/<story-id>.pat.yaml
121
+ ```
122
+
123
+ **Sub-task files: `<story-id>a.md`, `<story-id>b.md`, etc.**
124
+
125
+ One file per component. Each contains:
126
+ - Sub-task ID, title, component name, repo name
127
+ - Status and parent story reference
128
+ - The component's slice of the PATs as its acceptance criteria
129
+ - A `## PAT Stubs` section with test skeletons (one per PAT, using the
130
+ project's configured PAT framework)
131
+
132
+ ## Sub-task file format
133
+
134
+ ```
135
+ # <story-id><suffix>: <component-name>
136
+
137
+ **Type:** Technical Sub-Task
138
+ **Status:** Pending
139
+ **Parent:** <story-id>
140
+ **Component:** <component-name>
141
+ **Repo:** <repo-name>
142
+
143
+ ## Summary
144
+
145
+ <Brief description of what this component implements for this story.>
146
+
147
+ ## Acceptance Criteria (Repo-Level PATs)
148
+
149
+ 1. <PAT title>
150
+ - <detail>
151
+ - <detail>
152
+
153
+ 2. <PAT title> [replaces <old-story-id>/<old-sub-task-id> AC-N]
154
+ - <detail>
155
+ - Supersedes: <old-sub-task-id> AC-N (<brief description of what changed>)
156
+
157
+ ...
158
+
159
+ ## PAT Stubs
160
+
161
+ <Test skeletons — one per PAT, framework determined by project config>
162
+ ```
163
+
164
+ When a PAT declares `replaces` or `removes`, the sub-task file must
165
+ include this in the acceptance criteria section. This tells the
166
+ implementing agent:
167
+
168
+ - **replaces:** the old test for this AC must be updated or replaced
169
+ when compiling CATs. The old `.cy.js` or `.spec.js` file should be
170
+ modified to test the new behaviour, or the old test removed and a
171
+ new one written.
172
+ - **removes:** the old test should be deleted entirely. The feature
173
+ it tested no longer exists.
174
+
175
+ ### Step 4 — Compile story PAT and raise root MR
176
+
177
+ The root repo sub-task is not just documentation — its primary
178
+ deliverables (Cypress spec + integration test script) are mechanically
179
+ derivable from the story PAT. This step produces them and raises the
180
+ root MR so that the integration gate exists from the moment the story
181
+ is decomposed.
182
+
183
+ #### 4a — Compile story PAT → Cypress spec
184
+
185
+ Transform the story-level PAT YAML into `pats/<story-id>.cy.js` using
186
+ this mapping:
187
+
188
+ | PAT step | Cypress command |
189
+ |---|---|
190
+ | `navigate: /path` | `cy.visit('/path')` |
191
+ | `wait: "[data-testid='X']" is visible` | `cy.get('[data-testid="X"]').should('be.visible')` |
192
+ | `wait: "[data-testid='X']" contains "Y"` | `cy.get('[data-testid="X"]').should('contain', 'Y')` |
193
+ | `assert: "[data-testid='X']" is visible` | `cy.get('[data-testid="X"]').should('be.visible')` |
194
+ | `assert: "[data-testid='X']" contains "Y"` | `cy.get('[data-testid="X"]').should('contain', 'Y')` |
195
+ | `assert: "[data-testid='X']" count > N` | `cy.get('[data-testid="X"]').should('have.length.greaterThan', N)` |
196
+ | `assert: "[data-testid='X']" is disabled` | `cy.get('[data-testid="X"]').should('be.disabled')` |
197
+ | `assert: "[data-testid='X']" contains ""` | `cy.get('[data-testid="X"]').should('have.value', '')` |
198
+ | `click: "[data-testid='X']"` | `cy.get('[data-testid="X"]').click()` |
199
+ | `type: "[data-testid='X']" value "Y"` | `cy.get('[data-testid="X"]').type('Y')` |
200
+
201
+ Each AC becomes an `it()` block. The `when` field becomes the test
202
+ description. Order ACs so that tests with data dependencies run in
203
+ sequence (e.g. "add a todo" before "list shows todos").
204
+
205
+ ACs that require mutually exclusive starting states (empty vs populated)
206
+ should be ordered so the empty-state test runs first, then the add
207
+ action, then the populated-state test — building state as they go.
208
+
209
+ #### 4b — Create branch and commit
210
+
211
+ ```
212
+ scm.create_branch(repo: <root-repo>, branch: "feat/<story-id>d-integration-gate", ref: "main")
213
+ scm.push_files(repo: <root-repo>, branch: "feat/<story-id>d-integration-gate", files: [
214
+ { path: "pats/<story-id>.cy.js", content: <compiled-cypress-spec> }
215
+ ], commit_message: "✅ compile story PAT into Cypress spec for <story-id>")
216
+ ```
217
+
218
+ #### 4c — Raise root MR
219
+
220
+ ```
221
+ scm.create_merge_request(
222
+ repo: <root-repo>,
223
+ source_branch: "feat/<story-id>d-integration-gate",
224
+ target_branch: "main",
225
+ title: "<story-id>d: Story-level integration tests"
226
+ )
227
+ ```
228
+
229
+ The root MR exists from the moment the story is decomposed. Shadow
230
+ integration will see it in the completeness check. The Cypress tests
231
+ will fail until all components implement their parts — this is correct
232
+ behaviour. The gate is red until the story is genuinely complete.
233
+
234
+ ## Root repo sub-task format
235
+
236
+ The root repo sub-task has a distinct structure because its primary
237
+ deliverable is integration tests, not feature code:
238
+
239
+ ```
240
+ # <story-id><suffix>: root — Story-level integration
241
+
242
+ **Type:** Technical Sub-Task
243
+ **Status:** Pending
244
+ **Parent:** <story-id>
245
+ **Component:** root
246
+ **Repo:** <root-repo-name>
247
+
248
+ ## Summary
249
+
250
+ Story-level integration validation for <story-id>. Provides the
251
+ integration tests that gate shadow integration — no managed repo MR
252
+ can merge until these tests pass against the composed system.
253
+
254
+ ## Deliverables
255
+
256
+ 1. Cypress spec: `pats/<story-id>.cy.js`
257
+ - Compiled from story PAT — auto-generated during decomposition
258
+ - Full browser-based acceptance tests against composed system
259
+ - Committed to root repo MR at decomposition time
260
+
261
+ 2. Integration test script: `scripts/integration-tests/<story-id>.sh`
262
+ - Curl-based checks against the composed system
263
+ - Lightweight CI smoke test (runs without a browser)
264
+ - Runs automatically during shadow integration
265
+
266
+ 3. Compose config changes (if needed)
267
+ - Shared volumes, new services, environment variables
268
+ - Updates to docker-compose.yml
269
+
270
+ ## Integration Test Contract
271
+
272
+ The integration test script must:
273
+ - Exit 0 if all story-level checks pass
274
+ - Exit non-zero if any check fails
275
+ - Output clear descriptions of what passed and what failed
276
+ - Be runnable from the shadow:integration CI job (curl-based, no browser)
277
+ ```
278
+
279
+ ## Notes
280
+
281
+ - Sub-task IDs use alphabetic suffix: a, b, c, d (up to 26 components)
282
+ - The root repo sub-task is always the LAST suffix (e.g. if 3 managed
283
+ components get a/b/c, root gets d). This is convention, not a hard rule.
284
+ - PAT stubs are skeletons only — implementation happens in the repo
285
+ - The enriched story in the workspace is the source of truth for subsequent
286
+ scaffolding steps
287
+ - The readiness tracker is committed to the root repo under `stories/` — it
288
+ is the mechanism that tracks story progress through the Development phase.
289
+ Without it, there is no completeness gate for the merge transaction.
290
+ - Run `m-power scaffold-repo` against each sub-task file to create the repo
291
+ - The root repo sub-task is MANDATORY for every story. Shadow integration
292
+ will fail structurally (not logically) if no integration tests exist for
293
+ an in-flight story. This is by design — it forces the team to define
294
+ "done" before implementation begins.
295
+ - Two failure modes in shadow integration:
296
+ - **Structural failure:** story has open MRs but no integration test
297
+ script exists at `scripts/integration-tests/<story-id>.sh`
298
+ - **Logical failure:** integration tests exist but fail because not
299
+ all components have implemented their part yet