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.
- package/bin/m.mjs +76 -0
- package/dist-m/CHANGELOG.md +45 -0
- package/dist-m/capabilities/bootstrap-root-repo/SKILL.md +138 -0
- package/dist-m/capabilities/decompose-story/SKILL.md +299 -0
- package/dist-m/capabilities/generate-acceptance-tests/SKILL.md +305 -0
- package/dist-m/capabilities/generate-pats/SKILL.md +131 -0
- package/dist-m/capabilities/scaffold-repo/SKILL.md +641 -0
- package/dist-m/capabilities/setup-workspace/SKILL.md +70 -0
- package/dist-m/capabilities/tag-release/SKILL.md +121 -0
- package/dist-m/capabilities/wire-orchestration/SKILL.md +351 -0
- package/dist-m/m.md +126 -0
- package/dist-m/providers/provider-interface.md +191 -0
- package/dist-m/providers/scm/gitlab.md +377 -0
- package/dist-m/schemas/pat.schema.json +161 -0
- package/dist-m/schemas/project.schema.json +177 -0
- package/package.json +27 -0
- package/src/commands/changelog.mjs +58 -0
- package/src/commands/clone.mjs +199 -0
- package/src/commands/diff.mjs +29 -0
- package/src/commands/init.mjs +51 -0
- package/src/commands/update.mjs +41 -0
- package/src/commands/version.mjs +43 -0
- package/src/lib/copy.mjs +20 -0
- package/src/lib/detect-agent.mjs +25 -0
- package/src/lib/diff-trees.mjs +95 -0
- package/src/lib/topology.mjs +62 -0
- package/src/lib/version-file.mjs +25 -0
- package/src/lib/workspace.mjs +40 -0
- package/src/lib/wrappers/claude.mjs +54 -0
- package/templates/claude/skills/bootstrap-root-repo/SKILL.md +13 -0
- package/templates/claude/skills/decompose-story/SKILL.md +13 -0
- package/templates/claude/skills/generate-acceptance-tests/SKILL.md +13 -0
- package/templates/claude/skills/generate-pats/SKILL.md +13 -0
- package/templates/claude/skills/scaffold-repo/SKILL.md +13 -0
- package/templates/claude/skills/setup-workspace/SKILL.md +13 -0
- package/templates/claude/skills/tag-release/SKILL.md +13 -0
- package/templates/claude/skills/wire-orchestration/SKILL.md +13 -0
- 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
|