@eventmodelers/cli 1.0.138 → 1.0.139
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/package.json +1 -1
- package/stacks/classic/templates/.claude/skills/build-automation/SKILL.md +13 -2
- package/stacks/classic/templates/.claude/skills/build-state-change/SKILL.md +22 -6
- package/stacks/classic/templates/.claude/skills/build-state-view/SKILL.md +27 -8
- package/stacks/classic/templates/.claude/skills/learn-architecture/SKILL.md +83 -17
- package/stacks/classic/templates/.claude/skills/record-evidence/SKILL.md +177 -0
- package/stacks/classic/templates/build-kit/CLAUDE.md +10 -4
- package/stacks/classic/templates/build-kit/lib/backend-prompt.md +11 -6
- package/stacks/classic/templates/build-kit/lib/prompt.md +4 -2
- package/stacks/modeling-kit/templates/.claude/skills/detect-model-drift/SKILL.md +123 -84
- package/stacks/modeling-kit/templates/kit/CLAUDE.md +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eventmodelers/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.139",
|
|
4
4
|
"description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, OpenCQRS, UmaDB, Kurrent, or modeling-only)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -43,7 +43,7 @@ If `storylines[]` includes a beat sequence running through this automation's tri
|
|
|
43
43
|
|
|
44
44
|
## Step 3 — Find the trigger point
|
|
45
45
|
|
|
46
|
-
Locate where the trigger event's state change happens in the code
|
|
46
|
+
Locate where the trigger event's state change happens in the code — the **Slice map** in `ARCHITECTURE.md` names the code of the Done slice that produces it. If the map has a Done automation slice, build this one the way that one is built (same mechanism, registration and test style); otherwise pick the mechanism from `ARCHITECTURE.md`:
|
|
47
47
|
|
|
48
48
|
| Codebase has | Build the automation as |
|
|
49
49
|
|---|---|
|
|
@@ -57,6 +57,7 @@ Rules:
|
|
|
57
57
|
- The reaction must be **idempotent**: reprocessing the same trigger must not issue the command twice (check the resulting state, a processed-marker, or the todo-list query condition — whatever the codebase already uses).
|
|
58
58
|
- Follow the codebase's transaction boundaries: the command must not run inside a transaction that can still roll back the trigger unless the reference does exactly that.
|
|
59
59
|
- Never add a new messaging/scheduling library just for this slice.
|
|
60
|
+
- **Isolated and deletable**: the listener/consumer/job is its own class in the slice's own place (see *New slices — isolation*). Prefer subscribing to an existing event or querying for pending work over editing the trigger's service method; if a hook in that method is unavoidable (no event mechanism exists), keep it to a single call and list it under `Shared seams`.
|
|
60
61
|
|
|
61
62
|
## Step 4 — Register it
|
|
62
63
|
|
|
@@ -70,14 +71,24 @@ Besides the command tests from Step 2, write one test per `specifications[]` ent
|
|
|
70
71
|
|
|
71
72
|
Run the build command and the single-test command from `ARCHITECTURE.md` for the tests this slice added or changed. Do not run the full suite.
|
|
72
73
|
|
|
74
|
+
## Step 7 — Record the slice in the Slice map
|
|
75
|
+
|
|
76
|
+
Add (or update) this slice's row in the **Slice map** of `ARCHITECTURE.md`, with the trigger and every shared file it touched under `Shared seams`. Commit it with the slice.
|
|
77
|
+
|
|
78
|
+
## Step 8 — Record the evidence on the board
|
|
79
|
+
|
|
80
|
+
After the commit, invoke `/record-evidence`: it writes this slice's element → code mapping, field mapping, specification → test mapping, files, seams, assumptions and commit as a markdown note into the slice's column (chapter lane `Implementation`). Only then is the slice set to `Done`.
|
|
81
|
+
|
|
73
82
|
---
|
|
74
83
|
|
|
75
84
|
## Checklist
|
|
76
85
|
|
|
77
86
|
- [ ] The command was built (or reused) via build-state-change, with all its specifications tested
|
|
78
|
-
- [ ] The trigger uses the codebase's existing reactive mechanism, registered like the reference
|
|
87
|
+
- [ ] The trigger uses the codebase's existing reactive mechanism, registered like the precedent automation slice (or the reference)
|
|
88
|
+
- [ ] The automation is its own class; any hook into existing code is listed under `Shared seams` in its Slice map row
|
|
79
89
|
- [ ] Trigger → command field mapping matches slice.json exactly
|
|
80
90
|
- [ ] Reprocessing the same trigger does not issue the command twice
|
|
81
91
|
- [ ] Every specification has a passing test
|
|
82
92
|
- [ ] If `storylines[]` is present, its command segment is covered via build-state-change's storyline-derived tests
|
|
83
93
|
- [ ] No new framework, library or architectural style was introduced; any first-time mechanism choice is recorded in `ARCHITECTURE.md`
|
|
94
|
+
- [ ] The evidence note exists in the slice's column on the board (`/record-evidence`)
|
|
@@ -33,15 +33,19 @@ From the slice definition, extract:
|
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
36
|
-
## Step 2 —
|
|
36
|
+
## Step 2 — Find the precedent slices
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
This codebase is usually a legacy system whose event model was built from its code, so most neighbouring slices already exist in the code. Before writing anything, find out how they were built:
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
1. **Is this slice itself already in the code?** Look it up in the **Slice map** of `ARCHITECTURE.md` and search for the command name, event names, the entity and the key fields (also under their code names from *Code vs. board terms*). If it exists — a slice that reappears as `Planned`, or one the analysis found but never marked `Done` — this skill is a **diff**: update the existing code to match slice.json field by field, add missing specifications, remove fields slice.json no longer has. Never dismiss a mismatch as harmless drift, and don't rebuild it next to the existing code.
|
|
41
|
+
2. **Which existing slices are its neighbours?** From the Slice map and the context's `index.json`, pick the `Done` slices closest to this one — same context, same entity/aggregate, same events (e.g. the slice that produces this slice's `given` events, or another status transition on the same entity), same type. Read their `slice.json` and the code the map lists for them, **side by side**: that is exactly how a COMMAND, its EVENTs and its specifications from this board become code here. If no Done slice is close, fall back to the reference implementation in `ARCHITECTURE.md`.
|
|
42
|
+
3. **What does the slice build on?** Events this slice reads in its `given`/specifications that other Done slices produce are already persisted somewhere — reuse that entity/table, never re-implement or duplicate it.
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
If a Done slice in this context has no row in the Slice map, run `/learn-architecture slices` first.
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
## Step 3 — Map the slice the way its precedent is mapped
|
|
47
|
+
|
|
48
|
+
Take the precedent slice from Step 2 (or the **write** reference implementation from `ARCHITECTURE.md`) and build the same shape for this slice — same layers, naming, validation, error mapping and test style — placed as described in *New slices — isolation* of `ARCHITECTURE.md`:
|
|
45
49
|
|
|
46
50
|
| From slice.json | Becomes (per `ARCHITECTURE.md`) |
|
|
47
51
|
|---|---|
|
|
@@ -51,6 +55,7 @@ Open the **write** reference implementation from `ARCHITECTURE.md` and build the
|
|
|
51
55
|
| event that represents a status transition (`...Approved`, `...Cancelled`) | the field/status column update the codebase uses for such transitions |
|
|
52
56
|
|
|
53
57
|
Rules:
|
|
58
|
+
- **Isolated and deletable**: the slice's code lives in its own files (its own package/folder where the layout allows — see *New slices — isolation*), not as new methods appended to an existing shared service, controller or repository. Shared files are touched only at the seams `ARCHITECTURE.md` names (registration, routing, a new migration), each as one small, recognisable change. No other code may start depending on this slice's internals; it reaches shared state through the existing entity/repository. Removing the slice should mean deleting its files and reverting its seams.
|
|
54
59
|
- Every command field, every event field ends up somewhere concrete — persisted, validated or returned. A field with no destination is a gap: record your assumption.
|
|
55
60
|
- No fields that are not in slice.json. Technical columns the codebase always adds (ids, timestamps, version, audit) are fine if every comparable entity has them.
|
|
56
61
|
- Schema changes go through the codebase's migration mechanism — add a new migration, never edit an existing one.
|
|
@@ -84,6 +89,14 @@ Group these separately (own test class/`describe`/region, named after the storyl
|
|
|
84
89
|
|
|
85
90
|
Run the build command and the single-test command from `ARCHITECTURE.md` for the tests this slice added or changed. Do not run the full suite.
|
|
86
91
|
|
|
92
|
+
## Step 7 — Record the slice in the Slice map
|
|
93
|
+
|
|
94
|
+
Add (or update) this slice's row in the **Slice map** of `ARCHITECTURE.md`: entry point, persistence, tests, and every shared file it touched under `Shared seams` — that column is the checklist for deleting the slice later. Commit it with the slice.
|
|
95
|
+
|
|
96
|
+
## Step 8 — Record the evidence on the board
|
|
97
|
+
|
|
98
|
+
After the commit, invoke `/record-evidence`: it writes this slice's element → code mapping, field mapping, specification → test mapping, files, seams, assumptions and commit as a markdown note into the slice's column (chapter lane `Implementation`). Only then is the slice set to `Done`.
|
|
99
|
+
|
|
87
100
|
---
|
|
88
101
|
|
|
89
102
|
## Final Verification: Does the Implementation Match slice.json?
|
|
@@ -94,5 +107,8 @@ Run the build command and the single-test command from `ARCHITECTURE.md` for the
|
|
|
94
107
|
- [ ] If `storylines[]` is present, a storyline-derived test was added for every COMMAND beat
|
|
95
108
|
- [ ] No business rules, defaults, or constraints were added that do not appear in slice.json `description`, `comments` or specifications
|
|
96
109
|
- [ ] No field names were assumed or guessed — if a field is not in slice.json, it is not in the code
|
|
97
|
-
- [ ] The new code mirrors the reference implementation
|
|
110
|
+
- [ ] The new code mirrors its precedent slice (or the reference implementation): layout, naming and conventions; no new framework, library or architectural style was introduced
|
|
111
|
+
- [ ] Data produced by existing slices was reused, not duplicated
|
|
112
|
+
- [ ] The slice lives in its own files; shared files were touched only at the seams in `ARCHITECTURE.md`, and its Slice map row lists them
|
|
98
113
|
- [ ] Assumptions are recorded in `progress.txt` and as code comments
|
|
114
|
+
- [ ] The evidence note exists in the slice's column on the board (`/record-evidence`)
|
|
@@ -27,13 +27,22 @@ From the slice definition, extract:
|
|
|
27
27
|
- **readmodels[]** / **projections[]** / **queries[]** — the read model(s) this slice serves, with their fields
|
|
28
28
|
- the **events** feeding each read model — they tell you which persisted state the fields come from
|
|
29
29
|
- **specifications[]** — test scenarios (given events → expected read model)
|
|
30
|
-
- **storylines[]** (optional) — present only when the board author built an explicit walkthrough for this flow; most slices have none. See "Storyline-derived tests" under Step
|
|
30
|
+
- **storylines[]** (optional) — present only when the board author built an explicit walkthrough for this flow; most slices have none. See "Storyline-derived tests" under Step 6.
|
|
31
31
|
|
|
32
32
|
> **Comments & description**: each element carries a `comments: string[]` array (board comments) and a `description` field — use them as implementation hints, and resolve consumed comments via `POST <BASE_URL>/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/<nodeId>/comments/<commentId>/resolve`.
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
36
|
-
## Step 2 —
|
|
36
|
+
## Step 2 — Find the precedent slices
|
|
37
|
+
|
|
38
|
+
This codebase is usually a legacy system whose event model was built from its code, so most neighbouring slices already exist in the code. Before writing anything:
|
|
39
|
+
|
|
40
|
+
1. **Is this read already in the code?** Look the slice up in the **Slice map** of `ARCHITECTURE.md` and search for the read model name, its fields and the endpoint (also under the code names from *Code vs. board terms*). If it exists, this skill is a **diff** (see Step 3) — don't build a second query next to it.
|
|
41
|
+
2. **Which existing slices are its neighbours?** Pick the closest `Done` slices — the state-change slices that produce this read model's events (they show where the data is persisted), and another state-view slice in the same context or over the same entity (it shows how reads are built here). Read their `slice.json` and the code the map lists for them side by side. If no Done state-view is close, fall back to the read reference implementation in `ARCHITECTURE.md`.
|
|
42
|
+
|
|
43
|
+
If a Done slice in this context has no row in the Slice map, run `/learn-architecture slices` first.
|
|
44
|
+
|
|
45
|
+
## Step 3 — Locate the source data
|
|
37
46
|
|
|
38
47
|
For every read model field, find where the feeding event's data is persisted (the entity/table/column written by that event's state-change slice). Search by event name, entity and field names.
|
|
39
48
|
|
|
@@ -42,9 +51,9 @@ For every read model field, find where the feeding event's data is persisted (th
|
|
|
42
51
|
|
|
43
52
|
If the slice reappears as `Planned` and a query for it already exists, treat this skill as a **diff** against slice.json: add missing fields, remove fields slice.json no longer has, add missing specifications.
|
|
44
53
|
|
|
45
|
-
## Step
|
|
54
|
+
## Step 4 — Map the slice the way its precedent is mapped
|
|
46
55
|
|
|
47
|
-
|
|
56
|
+
Take the precedent state-view slice from Step 2 (or the **read** reference implementation from `ARCHITECTURE.md`) and build the same shape, with the same naming, placed as described in *New slices — isolation* of `ARCHITECTURE.md` — its own query class/DTO/endpoint files (own package/folder where the layout allows), not new methods appended to a shared repository or controller when a separate class works just as well. Shared files are touched only at the seams `ARCHITECTURE.md` names, and the query reads existing tables without changing them for other readers:
|
|
48
57
|
|
|
49
58
|
| From slice.json | Becomes (per `ARCHITECTURE.md`) |
|
|
50
59
|
|---|---|
|
|
@@ -55,11 +64,11 @@ Open the **read** reference implementation from `ARCHITECTURE.md` and build the
|
|
|
55
64
|
|
|
56
65
|
In an event-based codebase (per `ARCHITECTURE.md`), build the projection/read-model updater the existing way instead and register it like the reference does.
|
|
57
66
|
|
|
58
|
-
## Step
|
|
67
|
+
## Step 5 — Expose it
|
|
59
68
|
|
|
60
69
|
Expose the read the way comparable reads are exposed (REST endpoint, RPC, UI loader, ...), including registration, routing, API documentation and permission config, mirroring the reference. If the read is only consumed internally (e.g. by an automation's todo list), a service/repository method is enough.
|
|
61
70
|
|
|
62
|
-
## Step
|
|
71
|
+
## Step 6 — Write the tests
|
|
63
72
|
|
|
64
73
|
Write one executable test per entry in `specifications[]`, in the test style and location of the reference test:
|
|
65
74
|
|
|
@@ -80,10 +89,18 @@ A storyline is `{ id, title, elements: [...] }`, where `elements` is an ordered
|
|
|
80
89
|
|
|
81
90
|
Group these separately, named after the storyline. Skip a beat pair when a COMMAND beat sits in between (that half belongs to build-state-change) or when the run includes a SCREEN/AUTOMATION beat with no traceable event — a one-line comment noting the storyline segment exists is enough.
|
|
82
91
|
|
|
83
|
-
## Step
|
|
92
|
+
## Step 7 — Quality gate
|
|
84
93
|
|
|
85
94
|
Run the build command and the single-test command from `ARCHITECTURE.md` for the tests this slice added or changed. Do not run the full suite.
|
|
86
95
|
|
|
96
|
+
## Step 8 — Record the slice in the Slice map
|
|
97
|
+
|
|
98
|
+
Add (or update) this slice's row in the **Slice map** of `ARCHITECTURE.md`, including every shared file it touched under `Shared seams`. Commit it with the slice.
|
|
99
|
+
|
|
100
|
+
## Step 9 — Record the evidence on the board
|
|
101
|
+
|
|
102
|
+
After the commit, invoke `/record-evidence`: it writes this slice's element → code mapping, field mapping, specification → test mapping, files, seams, assumptions and commit as a markdown note into the slice's column (chapter lane `Implementation`). Only then is the slice set to `Done`.
|
|
103
|
+
|
|
87
104
|
---
|
|
88
105
|
|
|
89
106
|
## Checklist
|
|
@@ -93,5 +110,7 @@ Run the build command and the single-test command from `ARCHITECTURE.md` for the
|
|
|
93
110
|
- [ ] No parallel data store was invented for data that already exists
|
|
94
111
|
- [ ] Every specification has exactly one corresponding, passing test
|
|
95
112
|
- [ ] If `storylines[]` is present, a storyline-derived test was added for every isolable read-model transition (adjacent READMODEL beats with only EVENT beats between them)
|
|
96
|
-
- [ ] The new code mirrors the reference implementation
|
|
113
|
+
- [ ] The new code mirrors its precedent slice (or the reference implementation): layout, naming and conventions; no new framework, library or architectural style was introduced
|
|
114
|
+
- [ ] The slice lives in its own files; shared files were touched only at the seams in `ARCHITECTURE.md`, and its Slice map row lists them
|
|
97
115
|
- [ ] Assumptions and data gaps are recorded in `progress.txt` and as code comments
|
|
116
|
+
- [ ] The evidence note exists in the slice's column on the board (`/record-evidence`)
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: learn-architecture
|
|
3
|
-
description: Analyzes the existing codebase once and writes .build-kit/ARCHITECTURE.md — layers, feature layout, persistence, how writes/reads/background work are built, test style, build/test commands, and
|
|
3
|
+
description: Analyzes the existing codebase once and writes .build-kit/ARCHITECTURE.md — layers, feature layout, persistence, how writes/reads/background work are built, test style, build/test commands, and the slice map — which code every existing (Done) slice on the board corresponds to, and the mapping pattern they share. Run before the first slice is built, when ARCHITECTURE.md is missing or stale, or with `slices` when Done slices are missing from the slice map.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Learn Architecture
|
|
7
7
|
|
|
8
8
|
The classic build kit implements slices inside a codebase it did not create. Before any slice is built, the agent has to know how *this* codebase builds a feature — otherwise every slice drifts toward a generic pattern. This skill finds that out once and writes it down in `.build-kit/ARCHITECTURE.md`, which every `build-*` skill reads instead of re-exploring.
|
|
9
9
|
|
|
10
|
-
**
|
|
10
|
+
**The typical situation is a legacy system.** Someone ran a code base analysis (`analyze-code-base`), built the event model from the existing code, and now extends it. Most slices on the board therefore *already exist in the code* — usually in status `Done` — and their elements' `description`s carry code references (`path/to/File.java:57`, `Class#method`, tables, endpoints). Those slices are the most valuable input this skill has: each one is a worked example of how a COMMAND, EVENT, READMODEL or AUTOMATION from *this* board is realized in *this* code. The mapping is learned from them first, and from generic code reading only where no slice covers it.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**Arguments** (optional):
|
|
13
|
+
- `refresh` — re-analyze and rewrite `ARCHITECTURE.md` even if it exists.
|
|
14
|
+
- `slices` — keep everything else, only bring the **Slice map** up to date (Steps 2–3, then only the **Slice map** and *Code vs. board terms* sections in Step 6): add Done slices that are missing from it, re-check rows whose code moved.
|
|
15
|
+
|
|
16
|
+
If `.build-kit/ARCHITECTURE.md` exists and neither argument was passed: read it, then compare its **Slice map** against the `Done` slices in the local `index.json` files. If every Done slice has a row, return. Otherwise run as `slices`.
|
|
13
17
|
|
|
14
18
|
---
|
|
15
19
|
|
|
@@ -19,9 +23,37 @@ Read the build/dependency files at the project root and one level down (`package
|
|
|
19
23
|
|
|
20
24
|
Record: language + version, framework(s), persistence (database, ORM/query layer, migration tool), messaging if any, test framework(s), and the exact commands to build, run all tests, and run a **single** test file/class. Prefer what CI actually runs over what a README claims. Do not guess a command — if one can't be determined, say so in `ARCHITECTURE.md`.
|
|
21
25
|
|
|
22
|
-
## Step 2 —
|
|
26
|
+
## Step 2 — Collect the existing slices
|
|
27
|
+
|
|
28
|
+
Make sure the slice files are present (`/load-slice` without arguments refreshes all of them), then read every `.build-kit/.slices/*/index.json`. This is read-only reference work, so it covers **all** contexts, not only the current one.
|
|
29
|
+
|
|
30
|
+
Every slice with status `Done` is already implemented — treat it as a precedent. Slices in other statuses (`Created`, `Planned`, ...) may also carry code references from the analysis (the code exists, the slice was just never marked Done); include them when their descriptions point at code. Sort each slice by type the way `CLAUDE.md` *Building a Slice* does (state-change / state-view / automation / translation).
|
|
31
|
+
|
|
32
|
+
For each such slice, read its `slice.json` and collect the code references from:
|
|
33
|
+
- the `description` (and `comments`) of the slice and of every command, event, read model, screen and processor — paths with line numbers, `Class#method`, tables, endpoints, tests, templates;
|
|
34
|
+
- if the board is reachable and the chapter has them: the `Legacy Sources — <Chapter>` note (*Where this flow lives*) and the `Decisions — <column>` notes in the chapter's **Decisions** lane (`get_nodes { boardId, type: "MARKDOWN", projection: "line" }` for the ids, then read only the notes of chapters you need). They map elements to code with exact references and record code-vs-board term differences (`PetType` → *Species*).
|
|
35
|
+
|
|
36
|
+
A slice without any reference is located by search instead (Step 3).
|
|
37
|
+
|
|
38
|
+
## Step 3 — Map each existing slice onto its code
|
|
39
|
+
|
|
40
|
+
For every slice from Step 2, find the code that implements it. Open the referenced files (or search for the command/event/read model names, their fields, and the code terms from the Decisions notes) and record, per slice:
|
|
41
|
+
|
|
42
|
+
- **COMMAND** → entry point (endpoint/handler/action) + input DTO + service method
|
|
43
|
+
- **EVENT** → what it writes: entity/table + columns, status column + value, or the published event class
|
|
44
|
+
- **READMODEL** → query/repository method + response DTO + endpoint
|
|
45
|
+
- **AUTOMATION / processor** → listener/consumer/job + what it calls
|
|
46
|
+
- **Specifications** → the test class/method that covers them, if any
|
|
47
|
+
|
|
48
|
+
Verify, don't copy: a line number may be stale, a file may have moved. Fix the reference in the map; if a slice's code can't be found at all, record it as `not found` — never treat it as a feature to build, and never invent a location.
|
|
49
|
+
|
|
50
|
+
Then **look for the pattern across slices**. The same board construct is usually realized the same way every time — e.g. every `... Registered` event is an insert into the aggregate's table, every `... Approved/Cancelled` event is an update of a `status` column, every read model is a repository method + DTO in the same package, every automation is a `@Scheduled` job. That shared pattern *is* the Event Modeling mapping of this codebase (Step 5). Where slices are realized differently (two persistence styles, an old and a new module), record both and which slices use which, so a new slice can follow its nearest neighbour.
|
|
23
51
|
|
|
24
|
-
|
|
52
|
+
Do not read the whole codebase — follow the references.
|
|
53
|
+
|
|
54
|
+
## Step 4 — Fill the gaps with reference features
|
|
55
|
+
|
|
56
|
+
Only for what the existing slices don't cover (no Done slices at all, or e.g. no automation among them) pick **one or two existing features** that look like the slices the board will produce — something that accepts input and changes state, something that only reads/lists data. A recently changed, ordinary feature is a better reference than the oldest or the most special one (`git log --stat -20` helps). When existing slices cover a path, the best-mapped Done slice of that type *is* the reference implementation.
|
|
25
57
|
|
|
26
58
|
Trace each one end to end, reading only the files on that path:
|
|
27
59
|
|
|
@@ -32,9 +64,9 @@ Trace each one end to end, reading only the files on that path:
|
|
|
32
64
|
|
|
33
65
|
Do not read the whole codebase. Search (`grep`/glob) for a concept, then follow references.
|
|
34
66
|
|
|
35
|
-
## Step
|
|
67
|
+
## Step 5 — Decide the Event Modeling mapping
|
|
36
68
|
|
|
37
|
-
Decide how each board element is built **in this codebase**, based on what
|
|
69
|
+
Decide how each board element is built **in this codebase**, based on what the existing slices show (Step 3) and, only where they say nothing, on the reference features (Step 4) — not on Event Modeling theory:
|
|
38
70
|
|
|
39
71
|
- **Is it event-based?** Only if the code already persists or publishes events (event store, domain events, outbox, audit log of facts). Otherwise it is state-based (typically CRUD) and board EVENTs become the state transitions a command persists, not new event classes.
|
|
40
72
|
- **COMMAND** → which entry point + DTO + service method shape, and where business-rule violations go (exception type, result type, validation error).
|
|
@@ -43,7 +75,16 @@ Decide how each board element is built **in this codebase**, based on what you f
|
|
|
43
75
|
- **AUTOMATION / processor** → the existing reactive mechanism (or, if none exists, the least invasive option consistent with the codebase — usually a direct call or a scheduled job; note that choice explicitly).
|
|
44
76
|
- **Specification (given/when/then)** → how `given` events become pre-existing state in a test, and what `then` asserts on.
|
|
45
77
|
|
|
46
|
-
|
|
78
|
+
Then decide **where a new slice goes so it stays isolated and deletable**. Existing slices show how the code *is* built; new slices follow those conventions but are placed as self-contained as the codebase allows — ideally, removing a slice means deleting its own files plus undoing a short, known list of registrations. Settle, from what the codebase tolerates:
|
|
79
|
+
|
|
80
|
+
- **Own unit per slice** — the most local place the layout allows: a package/folder per slice inside the context's module (best), otherwise own files (controller, DTOs, service/handler, query, test) next to the comparable ones — never new methods appended to an existing shared service, controller or repository when a separate class registered the same way works just as well.
|
|
81
|
+
- **Shared seams** — the unavoidable touch points (router/DI registration, a menu entry, a schema migration, an existing entity that must gain a column) and how to keep each one to a single, small, recognisable change.
|
|
82
|
+
- **Dependencies between slices** — a new slice reads shared state through the existing entity/repository (or the codebase's query style), never by calling another slice's internals; no other slice depends on the new one.
|
|
83
|
+
- **Data** — new state goes into a new table or new columns via a new migration; existing columns are not repurposed.
|
|
84
|
+
|
|
85
|
+
Where the codebase genuinely forces a shared file (one big controller per aggregate, a central route file), follow it — and record that the slice touches it.
|
|
86
|
+
|
|
87
|
+
## Step 6 — Write `.build-kit/ARCHITECTURE.md`
|
|
47
88
|
|
|
48
89
|
Keep it short and concrete — paths, class names and commands, not prose. Use this structure:
|
|
49
90
|
|
|
@@ -65,27 +106,52 @@ Keep it short and concrete — paths, class names and commands, not prose. Use t
|
|
|
65
106
|
- Naming conventions (classes, files, endpoints, tables, columns)
|
|
66
107
|
|
|
67
108
|
## Reference implementations
|
|
68
|
-
|
|
109
|
+
Prefer a mapped Done slice per type; a plain feature only where no slice covers the type.
|
|
110
|
+
- Write: slice *Register Owner* — `path/to/Controller` → `path/to/Service` → `path/to/Repository` (+ migration)
|
|
69
111
|
- Read: ...
|
|
70
112
|
- Background: ... (or "none")
|
|
71
113
|
- Tests: `path/to/ReferenceTest` — how state is set up and asserted
|
|
72
114
|
|
|
73
115
|
## Event Modeling mapping
|
|
74
|
-
|
|
116
|
+
Derived from the slices in the Slice map — cite the slices that show each row.
|
|
117
|
+
| Board element | Built as | Seen in |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| COMMAND | ... | *Register Owner*, *Book Visit* |
|
|
120
|
+
| EVENT (creation) | ... | ... |
|
|
121
|
+
| EVENT (status transition) | ... | ... |
|
|
122
|
+
| READMODEL | ... | ... |
|
|
123
|
+
| AUTOMATION | ... | ... |
|
|
124
|
+
| Specification | ... | ... |
|
|
125
|
+
|
|
126
|
+
## Code vs. board terms
|
|
127
|
+
| Code | Board |
|
|
75
128
|
|---|---|
|
|
76
|
-
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
|
129
|
+
| `PetType` | *Species* |
|
|
130
|
+
|
|
131
|
+
## Slice map
|
|
132
|
+
Every slice that exists in the code. One row per slice; paths relative to the repo root. `Shared seams` lists the shared files a slice changed — for slices built by the kit it is the deletion checklist.
|
|
133
|
+
| Slice | Context | Type | Status | Command / entry point | Persistence (events) | Read / query | Trigger | Tests | Shared seams |
|
|
134
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
135
|
+
| Register Owner | owners | state-change | Done | `OwnerController#processCreationForm` → `OwnerService#register` | `owners` insert | — | — | `OwnerControllerTests` | legacy |
|
|
136
|
+
| Owner Details | owners | state-view | Done | `GET /owners/{id}` | — | `OwnerRepository#findById` → `OwnerDto` | — | ... | legacy |
|
|
137
|
+
| Remind Visit | visits | automation | Done | `VisitService#remind` | `visits.reminded_at` | — | `VisitReminderJob` (`@Scheduled`) | ... | legacy |
|
|
138
|
+
|
|
139
|
+
## New slices — isolation
|
|
140
|
+
- Placement: e.g. `src/main/java/org/acme/<context>/<slicename>/` with `<Slice>Controller`, `<Slice>Request`, `<Slice>Handler`, `<Slice>Test`
|
|
141
|
+
- Shared seams (the only shared files a slice may touch): `RouteConfig.java` (one line), `db/migration/V<n>__<slice>.sql` (new file), ...
|
|
142
|
+
- Codebase constraints that force sharing, and what to do then
|
|
81
143
|
|
|
82
144
|
## Rules
|
|
83
145
|
- Conventions a new slice must follow (transactions, validation, error mapping, auth, migrations append-only, ...)
|
|
84
146
|
- Files a slice must not touch (app bootstrap, global config, lockfiles, ...)
|
|
85
147
|
```
|
|
86
148
|
|
|
87
|
-
## Step
|
|
149
|
+
## Step 7 — Verify the commands
|
|
88
150
|
|
|
89
151
|
Run the build command and the single-test command against one existing test. If either fails for reasons unrelated to the code (missing service, missing env var), record the prerequisite under **Commands**. Do not "fix" the project to make it pass.
|
|
90
152
|
|
|
91
|
-
Commit `ARCHITECTURE.md` on its own: `chore: document architecture for build kit
|
|
153
|
+
Commit `ARCHITECTURE.md` on its own: `chore: document architecture for build kit` (with `slices`: `chore: update slice map`).
|
|
154
|
+
|
|
155
|
+
## Keeping the slice map current
|
|
156
|
+
|
|
157
|
+
The `build-*` skills add a row for every slice they build, so the map grows with the code. When a later code base analysis puts new Done slices on the board, the next build notices the missing rows and runs this skill with `slices` — only those slices are mapped, the rest of `ARCHITECTURE.md` stays as it is.
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: record-evidence
|
|
3
|
+
description: Writes the implementation evidence for a built slice onto the board — a markdown note in the slice's own column, in the chapter's "Implementation" feedback lane — listing the files, the board-element → code mapping, the specification → test mapping, the shared seams touched, assumptions and the commit. Run after the slice is committed, before it is set to Done. Also usable to document where an existing (legacy) Done slice lives in the code.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Record Evidence
|
|
7
|
+
|
|
8
|
+
> **Before doing anything else**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Do not proceed until the connect skill has completed.
|
|
9
|
+
|
|
10
|
+
Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect` skill) — the curl blocks below are the fallback for sessions without MCP connected. Send `x-agent-id: $EVENTMODELERS_AGENT_ID` on every write when it is set.
|
|
11
|
+
|
|
12
|
+
The evidence note is how a human reviewing the board sees **where** a slice lives in the code and **how** each modeled element and scenario was realized, without opening the repository. It is proof, not prose: every line names a concrete file, class, method, endpoint, table or test that exists in the commit.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Step 1 — Collect the evidence
|
|
17
|
+
|
|
18
|
+
From the slice you just built (or, for a legacy slice, from its row in the **Slice map** of `.build-kit/ARCHITECTURE.md` and the code it names):
|
|
19
|
+
|
|
20
|
+
| Item | Source |
|
|
21
|
+
|------|--------|
|
|
22
|
+
| `SLICE_ID`, slice title | `slice.json` → `id`, `title` |
|
|
23
|
+
| Commit | `git rev-parse --short HEAD` after the `feat: [Slice Name]` commit (`legacy` for a slice that pre-dates the kit) |
|
|
24
|
+
| Files created / modified | `git show --stat --format= HEAD` — repo-relative paths, split into *created* and *modified* |
|
|
25
|
+
| Element → code mapping | every COMMAND, EVENT, READMODEL, SCREEN and AUTOMATION in `slice.json` (with its `id`) and the code that realizes it |
|
|
26
|
+
| Field → code mapping | every command / event / read-model field and the parameter, property or column it maps to |
|
|
27
|
+
| Specification → test mapping | every entry in `specifications[]` (and storyline-derived tests) and the test class + method that covers it |
|
|
28
|
+
| Shared seams | the `Shared seams` column of the slice's Slice map row |
|
|
29
|
+
| Assumptions | the lines this slice added to `progress.txt` |
|
|
30
|
+
| Quality checks | the build and test commands from `ARCHITECTURE.md` you ran, and their result |
|
|
31
|
+
|
|
32
|
+
Only list what is really in the code. If an element has no counterpart (e.g. a modeled event the CRUD codebase has no equivalent for), say so explicitly — `— (persisted as the row insert, no event class)` — instead of leaving it out.
|
|
33
|
+
|
|
34
|
+
## Step 2 — Write the note
|
|
35
|
+
|
|
36
|
+
Reference board elements with `ref:<nodeId>` (the element ids from `slice.json`) so the note links back to them and keeps their current titles. Put code in backticks. Use this structure:
|
|
37
|
+
|
|
38
|
+
```markdown
|
|
39
|
+
# Implementation — <Slice Title>
|
|
40
|
+
|
|
41
|
+
**Commit** `<sha>` · **Type** <state-change|state-view|automation> · **Recorded** <YYYY-MM-DD> · **Checks** <build ✅ / tests ✅ (n passed)>
|
|
42
|
+
|
|
43
|
+
## Element → Code
|
|
44
|
+
| Element | Code | Where |
|
|
45
|
+
|---------|------|-------|
|
|
46
|
+
| ref:<commandId> | `RegisterMicrochipController#processCreationForm` — `POST /owners/{ownerId}/pets/{petId}/microchip/new` | `src/main/kotlin/.../microchip/RegisterMicrochipController.kt` |
|
|
47
|
+
| ref:<eventId> | insert into `microchips` via `MicrochipRepository#save` | `src/main/kotlin/.../microchip/MicrochipRepository.kt` |
|
|
48
|
+
|
|
49
|
+
## Fields
|
|
50
|
+
| Element | Field | Code |
|
|
51
|
+
|---------|-------|------|
|
|
52
|
+
| ref:<commandId> | `microchipNumber` | request param → `Microchip.microchipNumber` → column `microchips.microchip_number` |
|
|
53
|
+
|
|
54
|
+
## Specifications → Tests
|
|
55
|
+
| Specification | Test |
|
|
56
|
+
|---------------|------|
|
|
57
|
+
| <spec title> | `RegisterMicrochipControllerTest#<method>` |
|
|
58
|
+
|
|
59
|
+
## Files
|
|
60
|
+
**Created**
|
|
61
|
+
- `path/to/NewFile.kt`
|
|
62
|
+
|
|
63
|
+
**Modified (shared seams)**
|
|
64
|
+
- `path/to/schema.sql` — <what changed: new table / route / registration>
|
|
65
|
+
|
|
66
|
+
## Assumptions
|
|
67
|
+
- <one line each, or "none">
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Keep it compact: one row per element, field and specification — no code excerpts, no narrative. Paths are repo-relative.
|
|
71
|
+
|
|
72
|
+
## Step 3 — Locate the slice's column
|
|
73
|
+
|
|
74
|
+
The slice border carries its chapter and column: `parentId` is the chapter (timeline) id, `data.colId` the column id.
|
|
75
|
+
|
|
76
|
+
Prefer MCP:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
mcp__eventmodelers__get_node { "boardId": "<BOARD_ID>", "nodeId": "<SLICE_ID>" }
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Fallback (no MCP):**
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
curl -s -H "x-token: <TOKEN>" -H "x-user-id: record-evidence-skill" \
|
|
86
|
+
"<BASE_URL>/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/<SLICE_ID>"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Save `parentId` as `CHAPTER_ID` and `data.colId` (or `meta.colId`) as `COLUMN_ID`.
|
|
90
|
+
|
|
91
|
+
## Step 4 — Find or add the "Implementation" lane
|
|
92
|
+
|
|
93
|
+
Read the chapter's grid:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
mcp__eventmodelers__get_node { "boardId": "<BOARD_ID>", "nodeId": "<CHAPTER_ID>", "projection": "cells" }
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
curl -s -H "x-token: <TOKEN>" -H "x-user-id: record-evidence-skill" \
|
|
101
|
+
"<BASE_URL>/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/<CHAPTER_ID>?projection=cells"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
In `rows`, look for a row with `type: "feedback"` and label `Implementation` (case-insensitive). Save its `id` as `ROW_ID`.
|
|
105
|
+
|
|
106
|
+
**Never write into any other feedback lane** — other lanes (e.g. `Decisions`) belong to the modeling kit or to people. If there is no `Implementation` lane, add one:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
mcp__eventmodelers__add_lane { "boardId": "<BOARD_ID>", "timelineId": "<CHAPTER_ID>", "lanes": [{ "type": "feedback", "label": "Implementation" }] }
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
curl -s -X POST "<BASE_URL>/api/org/<ORG_ID>/boards/<BOARD_ID>/timelines/<CHAPTER_ID>/lanes" \
|
|
114
|
+
-H "Content-Type: application/json" -H "x-token: <TOKEN>" -H "x-user-id: record-evidence-skill" \
|
|
115
|
+
-d '{"type":"feedback","label":"Implementation"}'
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
and take `ROW_ID` from the response.
|
|
119
|
+
|
|
120
|
+
Then check `cells` for an entry with `rowId == ROW_ID` and `colId == COLUMN_ID`. If there is one, save its `nodeId` as `NOTE_ID` — this slice already has an evidence note (from an earlier build) and it gets **replaced**, not duplicated.
|
|
121
|
+
|
|
122
|
+
## Step 5 — Create or update the note
|
|
123
|
+
|
|
124
|
+
The note's content lives in `meta.description` (markdown source) — **not** `meta.content`, which is stored but never rendered.
|
|
125
|
+
|
|
126
|
+
**No note yet** — create it in the cell `<ROW_ID>-<COLUMN_ID>`:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
curl -s -X POST "<BASE_URL>/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/events" \
|
|
130
|
+
-H "Content-Type: application/json" -H "x-token: <TOKEN>" -H "x-user-id: record-evidence-skill" \
|
|
131
|
+
-d '[{
|
|
132
|
+
"id": "<new-random-uuid>",
|
|
133
|
+
"eventType": "node:created",
|
|
134
|
+
"nodeId": "<new-random-uuid>",
|
|
135
|
+
"chapterId": "<CHAPTER_ID>",
|
|
136
|
+
"cellId": "<ROW_ID>-<COLUMN_ID>",
|
|
137
|
+
"meta": {
|
|
138
|
+
"type": "MARKDOWN",
|
|
139
|
+
"title": "Implementation — <Slice Title>",
|
|
140
|
+
"description": "<markdown from step 2, JSON-escaped>"
|
|
141
|
+
}
|
|
142
|
+
}]'
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Note exists (`NOTE_ID`)** — replace its content:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
curl -s -X POST "<BASE_URL>/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/events" \
|
|
149
|
+
-H "Content-Type: application/json" -H "x-token: <TOKEN>" -H "x-user-id: record-evidence-skill" \
|
|
150
|
+
-d '[{
|
|
151
|
+
"id": "<new-random-uuid>",
|
|
152
|
+
"eventType": "node:changed",
|
|
153
|
+
"nodeId": "<NOTE_ID>",
|
|
154
|
+
"changedAttributes": ["meta.title", "meta.description"],
|
|
155
|
+
"meta": {
|
|
156
|
+
"type": "MARKDOWN",
|
|
157
|
+
"title": "Implementation — <Slice Title>",
|
|
158
|
+
"description": "<markdown from step 2, JSON-escaped>"
|
|
159
|
+
}
|
|
160
|
+
}]'
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
With MCP, send the same event through `mcp__eventmodelers__submit_node_events { "boardId": "<BOARD_ID>", "events": [ ... ], "autoConnect": false }`.
|
|
164
|
+
|
|
165
|
+
Build the JSON body with a tool that escapes properly (e.g. `jq -n --arg d "$(cat note.md)" ...` or a short script) — never hand-escape newlines and quotes.
|
|
166
|
+
|
|
167
|
+
## Step 6 — Verify and report
|
|
168
|
+
|
|
169
|
+
Read the note back (`GET .../nodes/<noteId>`) and check that `meta.description` is non-empty and every `ref:` id is one from `slice.json`. Then report:
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
Recorded evidence for "<Slice Title>" (<SLICE_ID>)
|
|
173
|
+
Note: <noteId> in lane Implementation, column <COLUMN_ID> (created|updated)
|
|
174
|
+
Commit: <sha>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
A failed write here never undoes the build: log it in `progress.txt` and continue with the status update — but do not skip this step silently.
|
|
@@ -4,11 +4,14 @@ This build kit was installed into an **existing codebase** — it ships no scaff
|
|
|
4
4
|
|
|
5
5
|
The codebase is typically a classic application (layered, CRUD, a relational database behind services/repositories) — but not necessarily: it may already use domain events, messaging, or event sourcing. Never assume; look.
|
|
6
6
|
|
|
7
|
+
The usual situation is a **legacy system being extended**: a code base analysis built the event model from the existing code, so most slices on the board — typically those in status `Done` — already exist in the code, and their elements' descriptions reference it. Those slices are the map from board to code: every new slice is built the way its closest existing slice is built.
|
|
8
|
+
|
|
7
9
|
## Architecture First
|
|
8
10
|
|
|
9
|
-
`.build-kit/ARCHITECTURE.md` describes how this codebase works: language, layers, where a feature's files go, persistence and migrations, how state changes are exposed (REST, RPC, UI actions), how reads are served, how background/reactive work is wired, the test style,
|
|
11
|
+
`.build-kit/ARCHITECTURE.md` describes how this codebase works: language, layers, where a feature's files go, persistence and migrations, how state changes are exposed (REST, RPC, UI actions), how reads are served, how background/reactive work is wired, the test style, the exact build/test commands — and the **Slice map**: which code every existing slice corresponds to, plus where a new slice goes so it stays isolated.
|
|
10
12
|
|
|
11
13
|
- If `.build-kit/ARCHITECTURE.md` does not exist, run `/learn-architecture` before building anything.
|
|
14
|
+
- If a `Done` slice in the local `index.json` files has no row in the Slice map, run `/learn-architecture slices` before building.
|
|
12
15
|
- Treat it as the authority for *how* to build. Treat `slice.json` as the authority for *what* to build.
|
|
13
16
|
- If the code contradicts `ARCHITECTURE.md` (a moved folder, a renamed base class, a wrong command), fix `ARCHITECTURE.md` in the same iteration rather than working around it.
|
|
14
17
|
|
|
@@ -18,6 +21,7 @@ The codebase is typically a classic application (layered, CRUD, a relational dat
|
|
|
18
21
|
- **No new architecture**: never introduce a new framework, library, persistence technology or architectural style (event store, CQRS bus, mediator, ...) to build a slice. If the codebase is CRUD, the slice is CRUD.
|
|
19
22
|
- **No dependency changes**: do not add or upgrade dependencies unless slice.json or a slice prompt explicitly asks for it.
|
|
20
23
|
- **Minimal footprint**: touch only the files the slice needs. Do not refactor, reformat or "clean up" unrelated code.
|
|
24
|
+
- **Isolated and deletable**: build each new slice as self-contained as the codebase allows — its own files (its own package/folder where the layout permits), shared files touched only at the seams `ARCHITECTURE.md` names (registration, routing, a new migration), no other code depending on its internals. Deleting a slice should mean deleting its files and reverting the seams listed in its Slice map row. Conventions still come from the codebase; isolation decides *where* the code goes, not *how* it is written.
|
|
21
25
|
|
|
22
26
|
Ignore case for files and slices in prompts. "CartItems" slice is the same as "cartitems".
|
|
23
27
|
|
|
@@ -37,7 +41,7 @@ When starting to work on a slice, invoke the `update-slice-status` skill with `I
|
|
|
37
41
|
When asked to build a slice, always follow this flow:
|
|
38
42
|
|
|
39
43
|
1. Read the slice definition from `.build-kit/.slices/<context>/<slicename>/slice.json`.
|
|
40
|
-
2. Make sure `.build-kit/ARCHITECTURE.md` exists — run `/learn-architecture`
|
|
44
|
+
2. Make sure `.build-kit/ARCHITECTURE.md` exists and its Slice map covers every `Done` slice — run `/learn-architecture` (or `/learn-architecture slices`) if not.
|
|
41
45
|
3. Determine the slice type:
|
|
42
46
|
- **Translation** — `sliceType === "TRANSLATION"` → read `description` and `notes` from slice.json for hints; default to `/build-automation` if nothing else is specified
|
|
43
47
|
- **Automation** — `processors` array is non-empty → invoke `/build-automation`
|
|
@@ -46,13 +50,15 @@ When asked to build a slice, always follow this flow:
|
|
|
46
50
|
4. Invoke the matching skill and follow its instructions completely. Do not deviate.
|
|
47
51
|
5. **Verify against slice.json**: After the skill completes, check that every command field, event field, read model field and specification in slice.json has its counterpart in the implementation. No invented fields — if it is not in slice.json, it must not be in the code. This applies even when the slice was previously `Done` and reappears as `Planned` — never dismiss a mismatch as "already implemented" or harmless drift; diff slice.json against the code field by field and update the code to match every change.
|
|
48
52
|
6. Run the quality checks from `.build-kit/ARCHITECTURE.md` (build/compile, then only the tests this slice touched).
|
|
49
|
-
7. If checks pass, commit with `feat: [Slice Name]
|
|
53
|
+
7. If checks pass, make sure the slice's row in the Slice map is added/updated and commit with `feat: [Slice Name]`.
|
|
54
|
+
8. Invoke `/record-evidence` — it writes the implementation evidence (element → code mapping, files, specification → test mapping, seams, assumptions, commit) as a markdown note into the slice's column, in the chapter's `Implementation` feedback lane.
|
|
55
|
+
9. Set slice status to `Done`.
|
|
50
56
|
|
|
51
57
|
After you are done, automatically run the tests for the slice that was edited.
|
|
52
58
|
|
|
53
59
|
## How Event Modeling maps onto this codebase
|
|
54
60
|
|
|
55
|
-
The board speaks Event Modeling; the codebase may not. `/learn-architecture`
|
|
61
|
+
The board speaks Event Modeling; the codebase may not. `/learn-architecture` derives the concrete mapping from the existing slices and records it in `ARCHITECTURE.md` — that mapping, and the closest `Done` slice's code, always beat the defaults below. The default for a CRUD codebase, used only where no existing slice shows the way, is:
|
|
56
62
|
|
|
57
63
|
| Board element | Typical CRUD counterpart |
|
|
58
64
|
|---|---|
|
|
@@ -4,6 +4,8 @@ You are an autonomous coding agent working on a software project. You apply your
|
|
|
4
4
|
|
|
5
5
|
This kit runs inside an **existing codebase** — nothing was scaffolded for you. The code is not necessarily event-sourced; typically it is a classic layered/CRUD application. The slice describes *what* must happen (commands, events, read models, specifications); the existing code decides *how* it is built. `.build-kit/ARCHITECTURE.md` is the record of how this codebase works — if it does not exist yet, run `/learn-architecture` before anything else.
|
|
6
6
|
|
|
7
|
+
Usually this is a legacy system being extended: the event model was built from the existing code, so most slices — typically those in status `Done` — already exist in the code. The **Slice map** in `ARCHITECTURE.md` says where; every new slice is built the way its closest existing slice is built, and placed as isolated and deletable as the codebase allows.
|
|
8
|
+
|
|
7
9
|
## Context Boundary (READ FIRST — NON-NEGOTIABLE)
|
|
8
10
|
|
|
9
11
|
You work within **exactly ONE context at a time** — the one named in `.build-kit/.slices/current_context.json`.
|
|
@@ -11,11 +13,12 @@ You work within **exactly ONE context at a time** — the one named in `.build-k
|
|
|
11
13
|
- **ONLY** look for and build slices inside `.build-kit/.slices/<currentContext>/`.
|
|
12
14
|
- **NEVER** read, scan, or build slices from any other context directory, even if it has "Planned" slices, and even if the current context has no work left.
|
|
13
15
|
- A "Planned" slice in a *different* context is **NOT yours to build**. Ignore it completely.
|
|
16
|
+
- The one exception is **reading** `Done` slices of other contexts as precedents (through the Slice map in `ARCHITECTURE.md`, or by `/learn-architecture` building that map) — they show how the codebase builds things, they are never built.
|
|
14
17
|
- If the current context has no "Planned" slice, you are **done for this iteration** — reply `<promise>NO_TASKS</promise>` and stop. Do not go looking elsewhere. The context is only ever changed on the board, never by you.
|
|
15
18
|
|
|
16
19
|
## Your Task
|
|
17
20
|
|
|
18
|
-
0. Do not read the entire code base. `.build-kit/ARCHITECTURE.md` tells you where to look; read the
|
|
21
|
+
0. Do not read the entire code base. `.build-kit/ARCHITECTURE.md` tells you where to look; read the code of the precedent slices its Slice map names and the files the slice actually touches. If a `Done` slice has no row in the Slice map, run `/learn-architecture slices` first.
|
|
19
22
|
1. Read `.build-kit/.slices/current_context.json` to find the active context name, then read `.build-kit/.slices/<contextName>/index.json`. Every item in status "planned" is a task.
|
|
20
23
|
2. Read the progress log at `progress.txt` **if it exists** (check Codebase Patterns section first) — it is absent until the first slice is built, which is not an error; create it when you write your first entry
|
|
21
24
|
3. Make sure you are on the right branch "feature/<slicename>", if unsure, start from main.
|
|
@@ -33,10 +36,11 @@ You work within **exactly ONE context at a time** — the one named in `.build-k
|
|
|
33
36
|
12. Make sure to write the ui-prompt.md as defined if defined in the skill
|
|
34
37
|
13. Run the quality checks listed in `.build-kit/ARCHITECTURE.md` — build/compile, then only the tests touched by this slice (do not run all tests).
|
|
35
38
|
14. If checks pass, commit ALL changes with message: `feat: [Slice Name]` and merge back to main as FF merge (update first)
|
|
36
|
-
15.
|
|
37
|
-
16.
|
|
38
|
-
17. Append your
|
|
39
|
-
18.
|
|
39
|
+
15. Invoke `/record-evidence` to write the implementation evidence (element → code mapping, files, specification → test mapping, seams, assumptions, commit) as a note into the slice's column, in the chapter's `Implementation` feedback lane.
|
|
40
|
+
16. Update the PRD to set `status: Done` for the completed story in index.json **and** update the slice status on the eventmodelers board using the `update-slice-status` skill (or MCP if available).
|
|
41
|
+
17. Append your progress to `progress.txt` after each step in the iteration.
|
|
42
|
+
18. Append your new learnings to `.build-kit/AGENTS.md` in a compressed form, reusable for future iterations. Only add learnings if they are not already there.
|
|
43
|
+
19. Finish the iteration.
|
|
40
44
|
|
|
41
45
|
## Escalating Ambiguity
|
|
42
46
|
|
|
@@ -93,7 +97,8 @@ Only update AGENTS.md if you have **genuinely reusable knowledge** that would he
|
|
|
93
97
|
- If a command there turns out to be wrong, fix it in `ARCHITECTURE.md` in the same iteration
|
|
94
98
|
- Do NOT commit broken code
|
|
95
99
|
- Keep changes focused and minimal
|
|
96
|
-
- Follow existing code patterns — match the architecture, naming and test style already in the codebase; never introduce a new framework, library or architectural style to build a slice
|
|
100
|
+
- Follow existing code patterns — match the architecture, naming and test style already in the codebase (the closest `Done` slice's code first); never introduce a new framework, library or architectural style to build a slice
|
|
101
|
+
- Keep each slice isolated and deletable: its own files, shared files only at the seams `ARCHITECTURE.md` names, listed in the slice's Slice map row
|
|
97
102
|
|
|
98
103
|
## Skills
|
|
99
104
|
|
|
@@ -54,7 +54,7 @@ This is the build trigger. Setting `InProgress` and building are one atomic step
|
|
|
54
54
|
|
|
55
55
|
2. Run `/load-slice sliceId=<payload.sliceId>` to fetch the full slice, then read the slice definition from `.build-kit/.slices/<contextSlug>/<sliceFolder>/slice.json`. The runner keeps a `slice.json` fresh from a summary endpoint, so a file holding only `id`, `title`, `status` and `sliceType` is that stub, not an empty slice — never conclude a slice has no elements from it. Only if the full fetch itself returns no commands/events/read models/fields is the slice actually empty.
|
|
56
56
|
|
|
57
|
-
3. Make sure `.build-kit/ARCHITECTURE.md` exists — if it is missing, run `/learn-architecture` first
|
|
57
|
+
3. Make sure `.build-kit/ARCHITECTURE.md` exists — if it is missing, run `/learn-architecture` first; if a `Done` slice has no row in its Slice map, run `/learn-architecture slices`. This kit installs into an existing codebase — usually a legacy system whose event model was built from its code, so most `Done` slices already exist in it. That file records how *this* project is built (layers, persistence, naming, tests, build/test commands) and which code each existing slice maps to; every `build-*` skill implements the slice the way its closest existing slice is built, kept as isolated and deletable as the codebase allows.
|
|
58
58
|
|
|
59
59
|
4. Determine the **slice type** from the slice.json:
|
|
60
60
|
- **Translation** — `sliceType === "TRANSLATION"` → read `description` and `notes` from slice.json for hints; default to `/build-automation` if nothing else is specified
|
|
@@ -70,7 +70,9 @@ This is the build trigger. Setting `InProgress` and building are one atomic step
|
|
|
70
70
|
|
|
71
71
|
8. If checks pass, commit all changes with message: `feat: [Slice Name]`.
|
|
72
72
|
|
|
73
|
-
9. Call `/
|
|
73
|
+
9. Call `/record-evidence` to write the implementation evidence (element → code mapping, files, specification → test mapping, seams, assumptions, commit) as a note into the slice's column on the board.
|
|
74
|
+
|
|
75
|
+
10. Call `/update-slice-status` to set the slice to `Done` on the board.
|
|
74
76
|
|
|
75
77
|
#### `InProgress`
|
|
76
78
|
Another agent is already building this slice. Log it and skip — do not build.
|
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: detect-model-drift
|
|
3
|
-
description:
|
|
3
|
+
description: Find where the code has moved away from the event model since the last analysis — reads the baseline commit from each chapter's first-column note (Analysis history), takes every commit since then as the changes made, and reports how the changed code now differs from the board (fields, specifications/tests, screens, edges, elements, slices). Changes on the board are out of scope — the model leads, the code follows. `--branch <name>` checks that branch's history instead of the current one. Read-only; every finding comes with a suggested fix the user confirms first.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Detect Model Drift
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
**Drift is a change in the code that the model doesn't reflect.** People model first and then have an agent build it, so a difference that comes from the board (a field renamed on the board, a new slice not built yet) is planned work, not drift, and this skill ignores it. What it looks for is the other direction: someone changed the code by hand (a manual commit, a hotfix, a refactoring) and the board no longer describes what the code does.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
So the skill looks at **the code changes since the last analysis**, nothing else:
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
1. the baseline is the commit of the last row in the chapter note's *Analysis history* (first column of the chapter),
|
|
13
|
+
2. every commit since then (plus uncommitted changes) is a change that was made,
|
|
14
|
+
3. for each change, compare what the code now does with what the board says. The differences are the drift.
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
## Step 0 — Is there a code base with history?
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
**Before anything else — before `connect`, before reading the board — resolve the directory to check**: `$EVENTMODELERS_CODE_DIR` if it is set (the agent runs from the global install and was started inside that directory — treat it as the repository root for every step below, not the current directory), otherwise the current directory.
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
- It must contain source code (e.g. `src/`, `.build-kit/`, a `package.json`, `pom.xml`, `build.gradle`, `*.csproj`, or similar). If it does not (an empty folder, a modeling-only workspace holding just `.claude/`, `.eventmodelers/` or `.agent-modeling-kit/`), **stop and answer in one or two plain sentences**, e.g.:
|
|
21
|
+
> Model drift can't be detected here — there is no code to compare the board against. Run this in the code base that implements the model.
|
|
22
|
+
- It must be a git repository (`git rev-parse --is-inside-work-tree`). If it is not, stop the same way: *"Drift is detected from the git history since the last analysis, and this code base has no git history. Run `/analyze-code-base` for a full analysis instead."*
|
|
23
|
+
|
|
24
|
+
Do not connect, do not read the board, and do not produce a report when either check fails.
|
|
25
|
+
|
|
26
|
+
**With `--branch <name>`** (see Step 1), check that the branch exists: `git rev-parse --verify <name>`, else `git fetch origin <name>` and `git rev-parse --verify origin/<name>`. Use whichever resolves as `REF`. If neither does, stop in one sentence (*"There is no branch `<name>` in this repository."*). Without `--branch`, `REF` is `HEAD`, and uncommitted changes in the working tree count too.
|
|
19
27
|
|
|
20
28
|
---
|
|
21
29
|
|
|
@@ -23,7 +31,7 @@ Do not connect, do not read the board, do not produce a report or snippet, and d
|
|
|
23
31
|
|
|
24
32
|
Prefer `mcp__eventmodelers__*` tools when available. See `learn-eventmodelers-api` for the curl fallback.
|
|
25
33
|
|
|
26
|
-
|
|
34
|
+
**This skill never changes the code**, and it changes the board only for what the person confirms — plus the one *Analysis history* row of Step 7.
|
|
27
35
|
|
|
28
36
|
---
|
|
29
37
|
|
|
@@ -33,158 +41,189 @@ From `$ARGUMENTS` and the prompt context, extract:
|
|
|
33
41
|
|
|
34
42
|
| Field | How to find it | Default |
|
|
35
43
|
|-------|---------------|---------|
|
|
36
|
-
| `timelineId` | `context.timelineId` of the prompt (overrules the prompt's own `timeline_id`), or a timeline/chapter named in the text |
|
|
44
|
+
| `timelineId` | `context.timelineId` of the prompt (overrules the prompt's own `timeline_id`), or a timeline/chapter named in the text | every chapter on the board |
|
|
37
45
|
| `contextName` | a bounded context named in the text | all contexts |
|
|
38
46
|
| `sliceTitle` | a single slice named in the text | all slices in scope |
|
|
39
|
-
| `branch` | `--branch <name>` in `$ARGUMENTS`, or a branch named in the text | the current branch
|
|
40
|
-
|
|
41
|
-
**If a timeline is in focus, only that timeline's slices are compared** — both on the board side and, through the slice → code mapping of Step 3, on the code side. Code that belongs to no slice in scope is not reported as "additional" in a scoped run; say so in the report footer instead of guessing.
|
|
47
|
+
| `branch` | `--branch <name>` in `$ARGUMENTS`, or a branch named in the text | the current branch (`HEAD` + working tree) |
|
|
48
|
+
| `since` | `--since <commit>` in `$ARGUMENTS`, or a commit named in the text | the baseline of Step 2 |
|
|
42
49
|
|
|
43
50
|
---
|
|
44
51
|
|
|
45
|
-
## Step 2 —
|
|
52
|
+
## Step 2 — Find the baseline (per chapter)
|
|
46
53
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
```
|
|
50
|
-
mcp__eventmodelers__list_slices { "boardId": "$BOARD_ID" }
|
|
51
|
-
mcp__eventmodelers__get_slice_data { "boardId": "$BOARD_ID", "contextName": "<CONTEXT>", "format": "toon" }
|
|
52
|
-
```
|
|
54
|
+
Every chapter carries its own baseline. For each chapter in scope:
|
|
53
55
|
|
|
54
|
-
|
|
56
|
+
1. `get_board_outline { boardId, chapterId }` and take the **first column's** MARKDOWN node in a `feedback` lane — the chapter note (`Legacy Sources — <Chapter>` when `/analyze-code-base` wrote it). Read it with `get_node` → `meta.description`.
|
|
57
|
+
2. Find its `## Analysis history` table and take the **Commit** of the **last row**. Strip a `+dirty` suffix (and note it: the files dirty back then are changed files too). Save it as `BASE`.
|
|
58
|
+
3. Check it: `git cat-file -e <BASE>^{commit}` and `git merge-base --is-ancestor <BASE> <REF>` — the baseline must be in this branch's history.
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
The rest of the note is context for judging findings too — *Where this flow lives* says which folders belong to the chapter, *Chapter decisions* and *Not modeled* say what is deliberately different or left out.
|
|
57
61
|
|
|
58
|
-
**
|
|
62
|
+
**No usable baseline** — no first-column note, no *Analysis history*, `no git`, or a hash that is unreachable or not an ancestor (rebased/squashed history): **don't fall back to comparing the whole board against the whole code.** Ask once which commit to start from, offering the most likely one: the newest commit recorded anywhere on the board for that chapter (an `Implementation — <Slice>` evidence note's **Commit**, a column note), or else the last few entries of `git log --oneline -10 <REF>`. A `since` argument answers this up front and overrules the note's baseline.
|
|
59
63
|
|
|
60
|
-
|
|
64
|
+
Chapters with the same baseline share one git read in Step 3.
|
|
61
65
|
|
|
62
66
|
---
|
|
63
67
|
|
|
64
|
-
## Step 3 —
|
|
68
|
+
## Step 3 — Collect the changes since the baseline
|
|
65
69
|
|
|
66
|
-
|
|
70
|
+
For each distinct `BASE`, list the commits and walk them **one by one, oldest first** — never judge from the net diff `<BASE>..<REF>` alone:
|
|
67
71
|
|
|
68
|
-
|
|
72
|
+
```bash
|
|
73
|
+
git log --reverse --format='%h %ad %an %s' --date=short <BASE>..<REF> # the commits, oldest first
|
|
74
|
+
git show --name-status --format= <sha> # the files one commit touched
|
|
75
|
+
git show <sha> -- <file> # that commit's change to one file
|
|
76
|
+
git diff <sha>..<REF> -- <file> # what happened to a file after a given commit
|
|
77
|
+
git status --porcelain && git diff HEAD # without --branch: uncommitted changes too
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Why per commit: when the range contains the commit that **created** a file (e.g. the build kit's `feat: <Slice>`), the net diff shows the file only as "added" with its final content, and a later hand edit (a renamed field, a removed check) disappears inside it — attributed to the build. Walking the commits keeps them apart. Never `git checkout`/`git switch` — read other refs with `git show <REF>:<path>`; the working tree may hold someone's uncommitted work.
|
|
69
81
|
|
|
70
|
-
|
|
71
|
-
2. Without a build kit, infer the layout from the repo (folders named after slices, `*Command*`, `*Event*`, projection/read-model files, route/UI files). If you cannot find any slice structure, stop and tell the user what you looked at — do not fabricate a mapping.
|
|
82
|
+
**Sort per file, not per commit.** One commit can mix kit or tooling files with real code (e.g. a commit that installs a kit *and* renames a field) — the noise files of that commit are dropped, its code files still count:
|
|
72
83
|
|
|
73
|
-
|
|
84
|
+
| Group | Examples | Handling |
|
|
85
|
+
|-------|----------|----------|
|
|
86
|
+
| **Behavior** | controllers/handlers, services, entities/aggregates, events, projections/queries, schema & migrations, validation, templates/UI, tests | compared in Step 5 |
|
|
87
|
+
| **Noise** | dependency bumps, build/CI config, gradle/maven wrappers, formatting-only diffs, docs, `.build-kit/`, `.claude/`, `.agent-modeling-kit/`, `.eventmodelers/`, `.mcp.json`, `CLAUDE.md`, `progress.txt`, generated files | listed in the report footer as *not relevant*, never a finding |
|
|
74
88
|
|
|
75
|
-
|
|
89
|
+
**Build-kit commits vs. hand-made commits.** A commit is the build kit's only if an `Implementation — <Slice>` evidence note names its sha, or — without evidence notes — its subject is `feat: <Slice Name>` for a slice on the board. It implemented the board, so its files are the **as-built state**: compare it cheaply against that slice only. Every other commit — including any commit after it that touches the same files — is a **hand-made change** and the main subject of this skill: for each file the build kit wrote, the drift candidates are `git diff <buildSha>..<REF> -- <file>`, attributed to the later commits.
|
|
76
90
|
|
|
77
|
-
|
|
91
|
+
No behavior changes since the baseline → report *"No code changes since `<BASE>` (<date of that row>) that affect the model"*, do Step 7, and stop.
|
|
78
92
|
|
|
79
93
|
---
|
|
80
94
|
|
|
81
|
-
## Step 4 —
|
|
95
|
+
## Step 4 — Map the changes to the board
|
|
82
96
|
|
|
83
|
-
|
|
97
|
+
For every behavior change, find the slice(s) and element(s) it belongs to. Use, in this order:
|
|
84
98
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
| **Fields** | On every COMMAND, EVENT and READMODEL: a field only in the model, a field only in the code, a name that differs (case or typo), a type that differs, `idAttribute` vs `@TargetEntityId`/event tag/aggregate key mismatch, optional vs required. |
|
|
90
|
-
| **Specifications** | A model GWT scenario with no test asserting it; a test (given/when/then) with no matching model scenario; a scenario whose events/fields no longer match the code. Storylines are narrative — compare their beats only for elements that no longer exist. |
|
|
91
|
-
| **Screens** | A SCREEN on the board with no UI counterpart; a UI screen/route/component wired to a slice's command or read model that the board doesn't show; a screen whose displayed read-model fields or submitted command fields differ from the model's dependencies. |
|
|
92
|
-
| **Edges** | Model dependency with no code counterpart, and the reverse: command → event (handler emits it), event → read model (projection consumes it), read model → screen, event → automation → command. A handler that emits an event the model doesn't connect, or a projection subscribing to events the model doesn't wire in. |
|
|
93
|
-
| **Elements** | An event/command/read model present on one side only, or a rename (same fields, different name). |
|
|
99
|
+
1. **`Implementation — <Slice>` evidence notes** (build kit, `Implementation` feedback lane, one per slice column): their *Element → Code*, *Fields*, *Specifications → Tests* and *Files* tables map code back to `ref:<nodeId>`s directly.
|
|
100
|
+
2. **`.build-kit/ARCHITECTURE.md` → Slice map**, if present: entry point, persistence, read/query, tests and shared seams per slice.
|
|
101
|
+
3. **The chapter note's** *Where this flow lives*, and the column decision notes' `Source` references (paths with line numbers).
|
|
102
|
+
4. Names: a command/event/read model/field whose name (or code name) appears in the changed code.
|
|
94
103
|
|
|
95
|
-
|
|
104
|
+
Then read the model **only for the slices you hit**: `get_slice_data { boardId, contextName, sliceId?, format: "toon" }` (full data: fields with types and `idAttribute`, dependencies, specifications, screens), and `get_node` for single elements. Don't read the rest of the board.
|
|
96
105
|
|
|
97
|
-
|
|
98
|
-
- **Direction matters.** A mismatch with no earlier evidence has no "right" side: propose the fix in the direction the evidence points (see Step 5), and say when it is a judgement call.
|
|
99
|
-
- Don't report framework noise: generated ids, metadata/envelope fields, serialization annotations, test fixtures' helper types, routes when the slice has no screen.
|
|
100
|
-
- Don't flag what is clearly intentional (an internal slice with no screen; a read model used only by another read model), or what the chapter's first-column feedback note (Step 2) describes as intended.
|
|
101
|
-
- Report each underlying difference **once**, at the element where it starts; a renamed field shows up on the command and the event and the read model — that is one finding listing the chain, not three.
|
|
106
|
+
A change that maps to no slice is itself a candidate finding — new behavior the board doesn't have (Step 5, *Element* / *Slice*). If it falls inside a chapter's *Where this flow lives* folders, it belongs to that chapter; otherwise say which chapter it most likely belongs to, or that it needs a new one.
|
|
102
107
|
|
|
103
108
|
---
|
|
104
109
|
|
|
105
|
-
## Step 5 —
|
|
110
|
+
## Step 5 — Compare the changed code with the board
|
|
106
111
|
|
|
107
|
-
|
|
112
|
+
Go change by change. Read the code **as it is at `REF`** (not just the diff hunk) for the elements the change touches, and compare it with what the board says about those elements. Every finding records: **kind**, **commit(s)** (short sha + subject + author), **file(s)** with line, **slice**, **element** (board `nodeId` where there is one), **what the board says**, **what the code now does**.
|
|
108
113
|
|
|
109
|
-
|
|
|
110
|
-
|
|
111
|
-
|
|
|
112
|
-
|
|
|
113
|
-
|
|
|
114
|
+
| Kind | A change in the code that … |
|
|
115
|
+
|------|------------------------------|
|
|
116
|
+
| **Fields** | adds, removes or renames a field/parameter/column on a command input, a persisted state (event) or a query result; changes its type, nullability/required-ness, or which field identifies the entity (`idAttribute`) |
|
|
117
|
+
| **Rules / specifications** | adds, removes or changes a validation, a guard, an error case or a default — or a test (given/when/then) — so that the board's GWT scenarios no longer describe the behavior |
|
|
118
|
+
| **Screens** | changes a UI template/component/route so that what it shows (read-model fields) or submits (command fields) differs from the board's SCREEN and its edges |
|
|
119
|
+
| **Edges** | makes a handler persist/emit something the board doesn't connect, a query read data the board doesn't wire in, a reaction (listener, job) trigger or issue something new — or removes such a connection |
|
|
120
|
+
| **Element** | adds a new command/state change/query/reaction, or removes or renames one the board has |
|
|
121
|
+
| **Slice** | adds a whole new feature (entry point + persistence/query) that is no slice on the board, or removes one the board says is `Done` |
|
|
114
122
|
|
|
115
|
-
|
|
123
|
+
Rules for judging:
|
|
116
124
|
|
|
117
|
-
|
|
125
|
+
- **Only changes since the baseline.** Code that was already different from the board at `BASE` is not this run's drift (the last analysis accepted it) — unless a change since then touched it.
|
|
126
|
+
- **Ignore everything that changed only on the board.** A board field the code never had, a `Planned` slice with no code, scenarios added after the build — that is planned work for the build kit, not drift. Don't report it, not even as a footnote.
|
|
127
|
+
- **A change that brings the code closer to the board is no finding** (e.g. a fix that finally implements a modeled scenario). Mention it in the summary at most.
|
|
128
|
+
- Don't flag what the chapter note's *Chapter decisions* / *Not modeled* or a column decision note explain as intended.
|
|
129
|
+
- No framework noise: generated ids, metadata/envelope fields, serialization annotations, test helpers, logging, refactorings that keep behavior (rename of a private method, extract class).
|
|
130
|
+
- **One difference, one finding**: a field renamed in the controller, the entity, the column and the template is one finding listing the chain, at the element where it starts.
|
|
118
131
|
|
|
119
132
|
---
|
|
120
133
|
|
|
121
|
-
## Step 6 —
|
|
134
|
+
## Step 6 — Propose the fix, show the findings, act only on confirmation
|
|
135
|
+
|
|
136
|
+
**The code change is the newer decision**, so the default fix is to **update the model** to describe what the code does now. The alternative is to treat the code change as a mistake and have the build kit bring the code back to the board.
|
|
137
|
+
|
|
138
|
+
| Finding | Recommended fix | Alternative |
|
|
139
|
+
|---------|-----------------|-------------|
|
|
140
|
+
| Field, rule/spec, screen, edge or element changed in code | **Model**: `/attributes` (fields), `/timeline` / `/place-element` (elements, edges), `/eventmodeling-elaborating-scenarios` (rules → GWT), `/html-screen` / `/storyboard-screen` (screens) | **Code**: `/update-slice-status` → `Planned` so the build kit rebuilds it from the board |
|
|
141
|
+
| New feature in code, no slice on the board | **Model**: place its elements, then `/eventmodeling-slicing-event-models` | **Code**: remove it — a decision for a human, never done from here |
|
|
142
|
+
| Board says `Done`, the code was removed | **Model**: remove the slice, or set it back to `Planned` if it is still wanted | — |
|
|
143
|
+
|
|
144
|
+
Recommend the alternative instead only when the change is evidently accidental (a typo like `custoemrId`, a debugging leftover, a disabled test) — say why.
|
|
145
|
+
|
|
146
|
+
**A model fix always includes the existing screens.** When a field, command or read model changes on the board, every SCREEN/HTML_SCREEN that shows or submits it changes with it — list each affected screen in the same finding (follow read model → screen and screen → command edges) and update it in place (`/html-screen` with its `nodeId`, `/storyboard-screen`). Never create a new screen next to an outdated one. **Never edit the code from this skill.**
|
|
122
147
|
|
|
123
148
|
Nothing is modified until the person answers.
|
|
124
149
|
|
|
125
150
|
### In a chat (`CHAT_SESSION_ID` is set)
|
|
126
151
|
|
|
127
|
-
Post **one** `post_chat_message` with a `tasks` snippet — the
|
|
152
|
+
Post **one** `post_chat_message` with a `tasks` snippet — the findings *and* the question which fixes to apply. Name the range in `text`, so the answering turn can read it back for Step 7:
|
|
128
153
|
|
|
129
154
|
```
|
|
130
155
|
mcp__eventmodelers__post_chat_message {
|
|
131
156
|
"boardId": "$BOARD_ID",
|
|
132
157
|
"sessionId": "<CHAT_SESSION_ID>",
|
|
133
|
-
"text": "
|
|
158
|
+
"text": "Since the last analysis (a1b2c3d → 9c1e2f0, 3 commits) the code changed in 2 places the board doesn't show. Tick the fixes to apply.",
|
|
134
159
|
"snippet": {
|
|
135
160
|
"kind": "tasks",
|
|
136
161
|
"headline": "Apply these fixes?",
|
|
137
162
|
"submitLabel": "Apply",
|
|
138
163
|
"tasks": [
|
|
139
|
-
{ "id": "d:model:<nodeId>:field:
|
|
140
|
-
{ "id": "d:code:<sliceId
|
|
164
|
+
{ "id": "d:model:<nodeId>:field:chipId", "title": "Rename field “microchipNumber” to “chipId” on Register Microchip and Microchip Registered", "description": "9c1e2f0 “chip id” renamed it in Microchip.kt and the controller after the slice was built — the board still says microchipNumber", "nodeId": "<nodeId>" },
|
|
165
|
+
{ "id": "d:code:<sliceId>:rule:uniqueness", "title": "Rebuild “Register Microchip” — the uniqueness check was removed in code", "description": "Sets the slice back to Planned", "nodeId": "<sliceId>" }
|
|
141
166
|
]
|
|
142
167
|
}
|
|
143
168
|
}
|
|
144
169
|
```
|
|
145
170
|
|
|
146
|
-
- `title` is the proposed fix, one sentence, plain language. `description`
|
|
171
|
+
- `title` is the proposed fix, one sentence, plain language. `description` names the commit (sha, subject, author) and what differs.
|
|
147
172
|
- `id` is `d:<model|code|decide>:<nodeId>:<kind>[:<detail>]` — the answering turn remembers nothing, so it must carry the direction and target. Put **every** finding in the one snippet (it pages itself at 5).
|
|
148
|
-
- Zero findings: a one-line text reply, no snippet
|
|
173
|
+
- Zero findings: a one-line text reply, no snippet, then Step 7.
|
|
149
174
|
|
|
150
|
-
The answer comes as a `CHAT` turn (`Please do these:` + ticked titles or ids). Read the snippet back with `get_chat_session`, match what was ticked, and create **one prompt** per direction: model fixes → *"Apply these model-drift fixes: `<id> | <title>` per line"*; code fixes → set each slice to `Planned`. Unticked fixes are declined — drop them.
|
|
175
|
+
The answer comes as a `CHAT` turn (`Please do these:` + ticked titles or ids). Read the snippet back with `get_chat_session`, match what was ticked, and create **one prompt** per direction: model fixes → *"Apply these model-drift fixes: `<id> | <title>` per line"*; code fixes → set each slice to `Planned`. Unticked fixes are declined — drop them. Then Step 7.
|
|
151
176
|
|
|
152
177
|
### Without a chat
|
|
153
178
|
|
|
154
|
-
Print the report below,
|
|
179
|
+
Print the report below, every finding as a `- [ ]` checkbox carrying its proposed fix, and ask which to apply. Wait for the answer, act on it, then Step 7.
|
|
155
180
|
|
|
156
|
-
Name each slice and element as `[<title>](ref:<nodeId>)` (the slice border's id for a slice)
|
|
181
|
+
Name each slice and element as `[<title>](ref:<nodeId>)` (the slice border's id for a slice); code that has no node stays plain text.
|
|
157
182
|
|
|
158
183
|
```
|
|
159
184
|
## Model Drift — <scope: board | timeline "<title>" | context "<name>">
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
### Slices
|
|
163
|
-
- [ ] <slice> — in code, not on the board → add it to the model
|
|
164
|
-
- [ ] [<slice>](ref:<sliceBorderId>) — board says Done, no code → set back to Planned
|
|
185
|
+
Changes: <BASE> (<date>, last analysis) → <REF short sha><, branch <name>><, + uncommitted> · <n> commits, <n> files with behavior changes Analysed: <ISO timestamp>
|
|
165
186
|
|
|
166
187
|
### Fields
|
|
167
|
-
- [ ] [<slice>](ref:<sliceBorderId>) / [<element>](ref:<nodeId>):
|
|
188
|
+
- [ ] [<slice>](ref:<sliceBorderId>) / [<element>](ref:<nodeId>): board says `microchipNumber`; `9c1e2f0 chip id` renamed it to `chipId` after the build (`7e3d1a2 feat: Register Microchip`) — `Microchip.kt:27`, `RegisterMicrochipController.kt:41`, both tests → rename the field on the command, the event and the screen
|
|
168
189
|
|
|
169
|
-
###
|
|
190
|
+
### Rules / Specifications · Screens · Edges · Elements · Slices
|
|
170
191
|
- [ ] ...
|
|
171
192
|
|
|
172
193
|
### Summary
|
|
173
|
-
<2–3 sentences:
|
|
174
|
-
|
|
194
|
+
<2–3 sentences: what changed in the code since the last analysis, how much of it the board is missing, the one fix worth doing first.>
|
|
195
|
+
Commits: <sha subject — one line each; mark build-kit commits>
|
|
196
|
+
Not relevant: <noise commits/files>
|
|
175
197
|
```
|
|
176
198
|
|
|
177
199
|
Omit empty sections. Say plainly when nothing drifted.
|
|
178
200
|
|
|
179
201
|
---
|
|
180
202
|
|
|
203
|
+
## Step 7 — Move the baseline forward
|
|
204
|
+
|
|
205
|
+
Once the person has answered (or there was nothing to report), append **one row** to the *Analysis history* of every chapter in scope (`node:changed` on that note's `meta.description` — never edit or drop earlier rows), so the next run starts from here:
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
| 4 | 2026-10-07 | `9c1e2f0` | drift check since `a1b2c3d` | `Microchip.kt`, `RegisterMicrochipController.kt` | 2 findings: 1 model fix applied, 1 declined |
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
- **Commit** is `REF`'s short sha; add `+dirty` when uncommitted changes were part of the check. With `--branch`, write `<sha> (<branch>)`.
|
|
212
|
+
- A declined finding is accepted as intended — that is why the baseline still moves past it; record it in the row so it can be found later.
|
|
213
|
+
- A chapter without a chapter note: don't create one here — say in the report that `/analyze-code-base` would add it, and that the next drift check needs `--since` until then.
|
|
214
|
+
- If the person never answers, the baseline stays where it was — the same changes come up again next time.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
181
218
|
## Learnings
|
|
182
219
|
|
|
183
|
-
-
|
|
184
|
-
-
|
|
185
|
-
-
|
|
186
|
-
-
|
|
187
|
-
-
|
|
188
|
-
-
|
|
189
|
-
-
|
|
190
|
-
-
|
|
220
|
+
- Drift = code changed, board didn't. Board-only changes are planned work for the build kit — never report them.
|
|
221
|
+
- The baseline is the last *Analysis history* row of the chapter's first-column note; the changes are `git log/diff <BASE>..<REF>` plus uncommitted work. No baseline → ask for a starting commit, never fall back to a whole-board comparison.
|
|
222
|
+
- The code change is the newer decision: recommend updating the model, unless the change is evidently accidental.
|
|
223
|
+
- Map changes to the board through the `Implementation — <Slice>` evidence notes and the Slice map first, names last; read only the slices hit.
|
|
224
|
+
- Walk the commits one by one and sort per file: a net diff hides a hand edit inside a file the build kit created in the same range, and one commit can mix kit-install noise with real code changes.
|
|
225
|
+
- A build-kit commit (evidence note names its sha, else `feat: <Slice>`) is the as-built state; every later change to its files is a hand-made change.
|
|
226
|
+
- No git history → no drift detection; say so in one line and stop (Step 0).
|
|
227
|
+
- `--branch` reads the code via `git show <REF>:<path>` — never check it out, the working tree may hold someone's uncommitted work.
|
|
228
|
+
- Every completed run appends one *Analysis history* row; an unanswered run doesn't move the baseline.
|
|
229
|
+
- `.build-kit/.slices` is no evidence of what the code was built from: every fetch, `/load-slice` and runner loop rewrites it.
|
|
@@ -413,7 +413,7 @@ nothing to sanitize either, since a board change is not user text.
|
|
|
413
413
|
| Business analysis, gap spotting, posting questions | `/wdyt` |
|
|
414
414
|
| Analyse the existing model structure, slice coverage, element counts | `/analyze-existing-model` |
|
|
415
415
|
| Reverse-engineer the business process of an existing code base into the model, as an interview — all chapters first, then one chapter at a time | `/analyze-code-base` |
|
|
416
|
-
| Find
|
|
416
|
+
| Find what changed in the code since the last analysis (git history from the chapter note's baseline) that the model doesn't reflect, and propose fixes | `/detect-model-drift` |
|
|
417
417
|
| Walk someone through a feature slice by slice, or through every slice a planned feature needs (existing, to adjust, new), as a player in the chat | `/walkthrough` |
|
|
418
418
|
| Turn a document or image (e.g. a tender/RFP) into a chaptered event model with screens, scenarios and a written blueprint summary | `/summarize` |
|
|
419
419
|
| Look up any API endpoint or element type not already covered by the skill you're executing | `/learn-eventmodelers-api` |
|