@milehimikey/em 1.11.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/event-modeling/SKILL.md +4 -2
- package/.claude/skills/event-modeling-conform/SKILL.md +20 -9
- package/.claude/skills/event-modeling-conform/reference/conform.md +107 -10
- package/.claude/skills/event-modeling-design/SKILL.md +22 -6
- package/.claude/skills/event-modeling-discover/SKILL.md +1 -1
- package/.claude/skills/event-modeling-implement/SKILL.md +12 -6
- package/.claude/skills/event-modeling-implement/reference/implement.md +165 -18
- package/.claude/skills/event-modeling-review/SKILL.md +5 -1
- package/.claude/skills/event-modeling-shared/reference/em-dsl.md +57 -8
- package/.claude/skills/event-modeling-shared/reference/operating-principles.md +13 -3
- package/.claude/skills/event-modeling-shared/reference/slice-doc-schema.md +69 -0
- package/.claude/skills/event-modeling-shared/templates/conformance-report.md +8 -1
- package/.claude/skills/event-modeling-shared/templates/constitution.md +8 -1
- package/.claude/skills/event-modeling-shared/templates/state.md +3 -0
- package/README.md +1 -0
- package/dist/catalog/build.js +42 -1
- package/dist/catalog/build.js.map +1 -1
- package/dist/catalog/coverage.d.ts +15 -0
- package/dist/catalog/coverage.js +34 -0
- package/dist/catalog/coverage.js.map +1 -0
- package/dist/catalog/docJoin.d.ts +20 -2
- package/dist/catalog/docJoin.js +32 -4
- package/dist/catalog/docJoin.js.map +1 -1
- package/dist/catalog/docModelConsistencyValidate.js +1 -1
- package/dist/catalog/docModelConsistencyValidate.js.map +1 -1
- package/dist/catalog/driftSignal.d.ts +11 -5
- package/dist/catalog/driftSignal.js +18 -4
- package/dist/catalog/driftSignal.js.map +1 -1
- package/dist/catalog/modelVersionValidate.d.ts +9 -0
- package/dist/catalog/modelVersionValidate.js +38 -0
- package/dist/catalog/modelVersionValidate.js.map +1 -0
- package/dist/catalog/noteBindingValidate.js +18 -0
- package/dist/catalog/noteBindingValidate.js.map +1 -1
- package/dist/catalog/orphanedSliceDocValidate.d.ts +8 -1
- package/dist/catalog/orphanedSliceDocValidate.js +33 -6
- package/dist/catalog/orphanedSliceDocValidate.js.map +1 -1
- package/dist/catalog/pages.d.ts +16 -1
- package/dist/catalog/pages.js +16 -4
- package/dist/catalog/pages.js.map +1 -1
- package/dist/catalog/sliceDoc.d.ts +12 -0
- package/dist/catalog/sliceDoc.js +15 -0
- package/dist/catalog/sliceDoc.js.map +1 -1
- package/dist/catalog/sliceReadyValidate.d.ts +12 -1
- package/dist/catalog/sliceReadyValidate.js +4 -4
- package/dist/catalog/sliceReadyValidate.js.map +1 -1
- package/dist/cli/agentsMd.js +9 -3
- package/dist/cli/agentsMd.js.map +1 -1
- package/dist/cli/ciInit.js +20 -0
- package/dist/cli/ciInit.js.map +1 -1
- package/dist/cli/conformScope.d.ts +1 -0
- package/dist/cli/conformScope.js +13 -4
- package/dist/cli/conformScope.js.map +1 -1
- package/dist/cli/conformSupersede.d.ts +24 -2
- package/dist/cli/conformSupersede.js +44 -3
- package/dist/cli/conformSupersede.js.map +1 -1
- package/dist/cli/coverage.d.ts +34 -9
- package/dist/cli/coverage.js +61 -24
- package/dist/cli/coverage.js.map +1 -1
- package/dist/cli/findings.d.ts +134 -0
- package/dist/cli/findings.js +355 -0
- package/dist/cli/findings.js.map +1 -0
- package/dist/cli/markImplemented.js +12 -1
- package/dist/cli/markImplemented.js.map +1 -1
- package/dist/cli/metrics.d.ts +93 -0
- package/dist/cli/metrics.js +331 -0
- package/dist/cli/metrics.js.map +1 -0
- package/dist/cli/modelVersion.d.ts +139 -0
- package/dist/cli/modelVersion.js +256 -0
- package/dist/cli/modelVersion.js.map +1 -0
- package/dist/cli/ratify.js +17 -1
- package/dist/cli/ratify.js.map +1 -1
- package/dist/cli/reratify.d.ts +17 -0
- package/dist/cli/reratify.js +37 -2
- package/dist/cli/reratify.js.map +1 -1
- package/dist/cli/review.js +12 -1
- package/dist/cli/review.js.map +1 -1
- package/dist/cli/skillCheck.js +2 -2
- package/dist/cli/skillCheck.js.map +1 -1
- package/dist/cli/sliceConform.d.ts +50 -0
- package/dist/cli/sliceConform.js +206 -0
- package/dist/cli/sliceConform.js.map +1 -0
- package/dist/cli/sliceIndex.d.ts +2 -0
- package/dist/cli/sliceIndex.js +24 -7
- package/dist/cli/sliceIndex.js.map +1 -1
- package/dist/cli/sliceLink.js +16 -0
- package/dist/cli/sliceLink.js.map +1 -1
- package/dist/cli/sliceNew.d.ts +12 -0
- package/dist/cli/sliceNew.js +23 -0
- package/dist/cli/sliceNew.js.map +1 -1
- package/dist/cli/sliceStubAll.d.ts +76 -0
- package/dist/cli/sliceStubAll.js +189 -0
- package/dist/cli/sliceStubAll.js.map +1 -0
- package/dist/cli/stateFile.d.ts +63 -7
- package/dist/cli/stateFile.js +179 -18
- package/dist/cli/stateFile.js.map +1 -1
- package/dist/cli/status.d.ts +90 -1
- package/dist/cli/status.js +151 -16
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/upgrade.d.ts +122 -0
- package/dist/cli/upgrade.js +476 -0
- package/dist/cli/upgrade.js.map +1 -0
- package/dist/cli.js +586 -66
- package/dist/cli.js.map +1 -1
- package/dist/emit/coverageJson.d.ts +2 -2
- package/dist/emit/coverageJson.js +6 -2
- package/dist/emit/coverageJson.js.map +1 -1
- package/dist/emit/freshnessJson.d.ts +1 -1
- package/dist/emit/freshnessJson.js +3 -1
- package/dist/emit/freshnessJson.js.map +1 -1
- package/dist/emit/json.d.ts +34 -1
- package/dist/emit/json.js +84 -2
- package/dist/emit/json.js.map +1 -1
- package/dist/emit/metricsJson.d.ts +7 -0
- package/dist/emit/metricsJson.js +27 -0
- package/dist/emit/metricsJson.js.map +1 -0
- package/dist/emit/statusJson.d.ts +1 -1
- package/dist/emit/statusJson.js +22 -1
- package/dist/emit/statusJson.js.map +1 -1
- package/dist/emit/upgradeJson.d.ts +5 -0
- package/dist/emit/upgradeJson.js +26 -0
- package/dist/emit/upgradeJson.js.map +1 -0
- package/dist/emit/validateJson.d.ts +10 -5
- package/dist/emit/validateJson.js +22 -8
- package/dist/emit/validateJson.js.map +1 -1
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +151 -22
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/continuation.d.ts +23 -0
- package/dist/model/continuation.js +49 -0
- package/dist/model/continuation.js.map +1 -0
- package/dist/model/queryIndex.js +1 -1
- package/dist/model/queryIndex.js.map +1 -1
- package/dist/model/rules.d.ts +13 -0
- package/dist/model/rules.js +18 -0
- package/dist/model/rules.js.map +1 -1
- package/dist/model/sliceDocIndex.d.ts +12 -5
- package/dist/model/sliceDocIndex.js +18 -7
- package/dist/model/sliceDocIndex.js.map +1 -1
- package/dist/model/validate.d.ts +20 -0
- package/dist/model/validate.js +94 -45
- package/dist/model/validate.js.map +1 -1
- package/dist/render/sliceStatus.d.ts +3 -3
- package/dist/render/sliceStatus.js +27 -29
- package/dist/render/sliceStatus.js.map +1 -1
- package/dist/templates.d.ts +3 -3
- package/dist/templates.js +15 -2
- package/dist/templates.js.map +1 -1
- package/dist/util/localDate.d.ts +2 -0
- package/dist/util/localDate.js +17 -0
- package/dist/util/localDate.js.map +1 -0
- package/dist/util/semver.d.ts +19 -0
- package/dist/util/semver.js +54 -0
- package/dist/util/semver.js.map +1 -0
- package/package.json +1 -1
|
@@ -49,17 +49,27 @@ em slice new <name> --pattern <pattern> # slice pattern: s
|
|
|
49
49
|
em slice new <name> --swimlane <swimlane> # swimlane, e.g. "Persona → Context"
|
|
50
50
|
em slice new <name> -f, --force # overwrite the file if it already exists
|
|
51
51
|
em slice new <name> --wire <model-file> # also insert the `note "slices/<key>.md"` line onto the slice's primary element in this .em file (matched by export key), instead of just printing it to paste by hand (MIL-161)
|
|
52
|
+
em slice new <name> --stub # write a near-free stub instead: same 5 frontmatter keys, but a one-line placeholder body instead of the diagram-image stub and every judgment section (MIL-184) — deepen it later by re-running without --stub and -f
|
|
53
|
+
em slice stub-all <file> # scaffold + wire a near-free stub (`em slice new --stub`'s content, MIL-184) for every slice in <file> with no resolvable doc — the fast path to status coloring for an exploratory/backbone model without hand-running `slice new` per slice. Skips a continuation slice (MIL-208, it has no doc of its own), an already-documented slice, and a slice whose pattern can't be classified
|
|
54
|
+
em slice stub-all <file> --status <status> # target status for every stub: draft | reviewed | ready-to-implement | implemented
|
|
55
|
+
em slice stub-all <file> --by <name> # identity for reviewedBy/ratifiedBy — required unless --status draft
|
|
56
|
+
em slice stub-all <file> --implemented-in <url> # PR/commit URL for implementedIn — required with --status implemented
|
|
57
|
+
em slice stub-all <file> --dry-run # list what would be stubbed/wired without writing anything
|
|
52
58
|
em slice index <file> # rewrite the model's sibling README.md's GENERATED Slices table from `em export`'s slice facts (key, pattern, doc status/implementedIn) — the hand-maintained table is deprecated
|
|
53
59
|
em slice index <file> --check # verify the table is current; exit non-zero on drift without writing (CI)
|
|
54
60
|
em slice mark-implemented <file> <slice-key> <pr-url> # flip a slice doc's frontmatter to `status: implemented` / `implementedIn: <pr-url>` — the one edit an implementing agent makes to a ratified doc at merge (MIL-103, replaces the em-sdd-bridge `em-sdd-mark-implemented` script; see reference/implement.md §6). Idempotent on the same URL; refuses to overwrite a different one; never touches `version:` or the doc body
|
|
55
61
|
em slice review <file> <slice-key> # flip a slice doc's frontmatter to `status: reviewed` and record `reviewedBy:`/`reviewedOn:` — the FIRST of the two human gates (MIL-201, docs/process.md#the-slice-lifecycle-gates): the room walked this slice and every open question it raised is resolved. Ratification is a separate, later gate (`em slice ratify`). Legal from `status: draft`; idempotent on the same --by/--on pair; refuses to overwrite a different one already recorded; refuses a doc already `ready-to-implement`/`implemented`; never touches `version:` or the doc body
|
|
56
62
|
em slice review <file> <slice-key> --by <name> # the reviewer's (or facilitator's) name
|
|
57
|
-
em slice review <file> <slice-key> --on <date> # review date, YYYY-MM-DD (default: today)
|
|
63
|
+
em slice review <file> <slice-key> --on <date> # review date, YYYY-MM-DD (default: today, local date)
|
|
58
64
|
em slice ratify <file> <slice-key> # flip a slice doc's frontmatter to `status: ready-to-implement` and record `ratifiedBy:`/`ratifiedOn:` — the handoff sign-off (MIL-165, docs/process.md#the-slice-lifecycle-gates) that makes who ratified, and when, a first-class recorded fact. Refuses a doc that never passed the review gate (`em slice review`) unless --skip-review is passed. Idempotent on the same --by/--on pair; refuses to overwrite a different one already recorded; never touches `version:` or the doc body
|
|
59
65
|
em slice ratify <file> <slice-key> --by <name> # the ratifier's name
|
|
60
|
-
em slice ratify <file> <slice-key> --on <date> # ratification date, YYYY-MM-DD (default: today)
|
|
66
|
+
em slice ratify <file> <slice-key> --on <date> # ratification date, YYYY-MM-DD (default: today, local date)
|
|
61
67
|
em slice ratify <file> <slice-key> --skip-review # ratify without a recorded review — prints a loud notice on stderr
|
|
62
68
|
em slice reratify <file> <slice-key> # bump `version:` and flip a shipped slice doc's frontmatter back to `status: ready-to-implement` — the re-ratification mechanical edit (MIL-161, mirrors `em slice mark-implemented`). Only applies to a doc at `status: implemented`; clears any stale `ratifiedBy:`/`ratifiedOn:`/`reviewedBy:`/`reviewedOn:` (they describe the PRIOR version's review and sign-off) so a follow-up `em slice ratify --by` applies cleanly — and needs no fresh review; never touches `implementedIn:` or the doc body
|
|
69
|
+
em slice conform <file> <slice-key> # record per-slice-per-version conformance certification: sets `conformedVersion:`/`conformedAt:`/`conformedOn:` on a slice doc (MIL-214) — the fact `driftSignal: in-sync` now depends on. Legal only for `status: implemented` with an `implementedIn:` link. Idempotent on the same (version, --at) pair; a different --at simply overwrites (a later re-certification is normal — there's no way for em to tell 'later' from 'earlier' for an arbitrary revision string, so there's no --force to reach for). Refuses when the newest conformance/*-findings.json matching --at still has an unruled finding in scope for this slice; --skip-findings-check overrides with a loud notice.
|
|
70
|
+
em slice conform <file> <slice-key> --at <rev> # the target-repo revision this certification sweep diffed against
|
|
71
|
+
em slice conform <file> <slice-key> --on <date> # certification date, YYYY-MM-DD (default: today, local date)
|
|
72
|
+
em slice conform <file> <slice-key> --skip-findings-check # certify even with unruled findings in scope — prints a loud notice on stderr
|
|
63
73
|
em changelog <file> # render a model's git history as a business-readable ledger (see docs/cli.md)
|
|
64
74
|
em changelog <file> --from <rev> # start the walk at this revision (inclusive)
|
|
65
75
|
em changelog <file> --to <rev> # end the walk at this revision (inclusive; default HEAD)
|
|
@@ -67,21 +77,32 @@ em changelog <file> -o, --out <path> # write to a file
|
|
|
67
77
|
em state read [dir] # print the state file's mechanical fields as JSON
|
|
68
78
|
em state set-phase <phase> [dir] # rewrite Current phase: (and Last updated:); --step also rewrites Current step:
|
|
69
79
|
em state set-phase <phase> [dir] --step <n> # also set Current step: to this value
|
|
70
|
-
em state set-conformance <revision> [dir] # rewrite Last conformance: (and Last updated:) in the exact format reference/conform.md parses
|
|
80
|
+
em state set-conformance <revision> [dir] # rewrite Last conformance: (and Last updated:) in the exact format reference/conform.md parses. Refuses (MIL-214) while any `implemented` slice has an unruled conformance finding in the findings JSON beside --report (a `slice: null` finding blocks every slice); --partial records the marker with a ` (partial)` suffix instead, with a loud notice. Without a findings JSON beside --report: warns once and records the marker as given (migration path for a report predating `em conform-findings`)
|
|
71
81
|
em state set-conformance <revision> [dir] --report <path> # path to the conformance report just written
|
|
82
|
+
em state set-conformance <revision> [dir] --partial # record the marker as PARTIAL even though some in-scope findings are still unruled
|
|
72
83
|
em state set-review <date> [dir] # rewrite Last stakeholder review: (and Last updated:)
|
|
73
84
|
em state log-usage <file> # append one Usage log line — phase(s) touched + em validate's diagnostic categories hit, deduped and canonically formatted (MIL-161, docs/usage-data.md) — the mechanical half of 'save state at the end of every session' that used to be run-validate-then-hand-format; state file resolved next to <file>, same convention as em conform-scope
|
|
74
85
|
em state log-usage <file> --phases <list> # comma-separated phase(s) touched this session: discover, extract, model, slice, implement, conform, review, validate, watch
|
|
86
|
+
em model version bump <file> # bump the model's design version: write model-versions/v<N+1>.json (sibling of slices/, conformance/) and rewrite the state file's `Model version:` bullet (MIL-218). Refuses when the state file is missing (run `em scaffold` first), when --by is empty, and when nothing has changed since the current version (same model content hash AND same slice-version vector) unless --force — a no-op bump is the one case --force is right for.
|
|
87
|
+
em model version bump <file> --by <name> # the bumper's name
|
|
88
|
+
em model version bump <file> --on <date> # bump date, YYYY-MM-DD (default: today, local date)
|
|
89
|
+
em model version bump <file> --force # bump even though nothing has changed since the current version
|
|
90
|
+
em model version show <file> # print the model's current design version and the most recently certified version, if any (model-versions/*.json — MIL-218)
|
|
91
|
+
em model version show <file> --json # print a JSON document instead of text
|
|
75
92
|
em usage-report [root] # aggregate every .event-modeling.md's Usage log under [root] into phase/diagnostic-category tallies (MIL-161) — replaces docs/usage-data.md's hand-rolled grep/awk/sort pipeline; a logged line that doesn't match the canonical em state log-usage format is reported under unparseableLines rather than silently mistallied or dropped
|
|
76
93
|
em usage-report [root] --json # print a JSON document instead of the text report
|
|
77
94
|
em conform-scope <file> # mechanize conform phase step 1 (reference/conform.md): map the target repo's changed paths since Last conformance: to slices via each slice doc's implementedIn, JSON to stdout — --seed-asis also seeds the <model>-asis.em scratch model (see docs/cli.md)
|
|
78
95
|
em conform-scope <file> --repo <path> # path to (or inside) the target codebase's git repository
|
|
79
96
|
em conform-scope <file> --full # ignore Last conformance:/changed paths; scope every implemented slice
|
|
80
97
|
em conform-scope <file> --seed-asis # write <model>-asis.em as a byte copy of the canonical model and ensure it's gitignored
|
|
81
|
-
em conform-supersede <file> <report-path> # stamp a conformance report with a "superseded as of <rev>" banner once its findings have been ruled on (MIL-164, docs/process.md#what-ratified-means) — the companion step to run at ratification time so a reader following the report's file:line citations knows they describe an ancestor of the current model. Additive-only splice, never a rewrite of the report; idempotent on the same --as-of/--findings/--on stamp; refuses if the report doesn't exist
|
|
98
|
+
em conform-supersede <file> <report-path> # stamp a conformance report with a "superseded as of <rev>" banner once its findings have been ruled on (MIL-164, docs/process.md#what-ratified-means) — the companion step to run at ratification time so a reader following the report's file:line citations knows they describe an ancestor of the current model. Additive-only splice, never a rewrite of the report; idempotent on the same --as-of/--findings/--on stamp; refuses if the report doesn't exist. --locus/--by (MIL-214, both required together) additionally record the ruling itself — locus/resolvedBy/resolvedOn — on the findings named by --findings in the sibling conformance/<date>-findings.json, when one exists (warns once and stamps the banner only when it doesn't — the migration path for a report predating em conform-findings)
|
|
82
99
|
em conform-supersede <file> <report-path> --as-of <rev> # the revision this ruling was made against — same value passed to `em state set-conformance`
|
|
83
100
|
em conform-supersede <file> <report-path> --findings <spec> # which finding number(s) this stamps as ruled, e.g. "1-3" or "1,2,4"
|
|
84
|
-
em conform-supersede <file> <report-path> --on <date> # ruling date, YYYY-MM-DD (default: today)
|
|
101
|
+
em conform-supersede <file> <report-path> --on <date> # ruling date, YYYY-MM-DD (default: today, local date)
|
|
102
|
+
em conform-supersede <file> <report-path> --locus <locus> # who/what the named finding(s) say is wrong: model | doc | code | none (requires --by)
|
|
103
|
+
em conform-supersede <file> <report-path> --by <name> # who ruled on the named finding(s) (requires --locus)
|
|
104
|
+
em conform-findings check <path> # shape-validate a conformance/<date>-findings.json file (findingsSchemaVersion, required fields, enum values, ids sorted+unique, a ruled finding carries resolvedBy+resolvedOn) — exit 1 on shape errors. The conform skill writes this file directly alongside its report; this is how a headless run verifies what it just wrote.
|
|
105
|
+
em conform-findings check <path> --json # print a JSON document instead of the text report
|
|
85
106
|
em watch <file> # re-render on every save
|
|
86
107
|
em watch <file> -o, --out <path> # output path (extension picks the format)
|
|
87
108
|
em watch <file> -T, --format <fmt> # output format (svg, png, pdf, ...)
|
|
@@ -102,9 +123,10 @@ em ledger <file> --from <rev> # baseline revisio
|
|
|
102
123
|
em ledger <file> --to <rev> # compare revision (default: current working tree)
|
|
103
124
|
em ledger <file> --waive <slice-key> # excuse a doc-content-without-version-bump finding for this slice key (repeatable; MIL-185, see docs/cli.md) — never waives a version regression or bump-without-content-change
|
|
104
125
|
em ledger <file> --json # print a JSON document instead of the text report (see docs/cli.md)
|
|
105
|
-
em coverage <file> # check that every INV-* invariant ID cited in
|
|
126
|
+
em coverage <file> # check that every INV-* invariant ID cited in an implemented slice doc is cited by a test under --tests <dir> (MIL-130/MIL-207) — mechanizes reference/implement.md's definition-of-done citation check; advisory by default, --strict for CI; --include-ready also counts ready-to-implement docs (forward-looking report); a continuation slice (an `again` view instance with no doc of its own, MIL-208) is excluded from the report — its invariants, if any, live in the originating slice's own doc
|
|
106
127
|
em coverage <file> --tests <dir> # directory to scan recursively for test files citing invariant IDs
|
|
107
128
|
em coverage <file> --strict # exit non-zero if any invariant ID has zero citations (CI)
|
|
129
|
+
em coverage <file> --include-ready # also count ready-to-implement docs, not just implemented (MIL-207)
|
|
108
130
|
em coverage <file> --json # print a JSON document instead of the text report (see docs/cli.md)
|
|
109
131
|
em status <files> # deterministic state-of-the-system rollup over one or more .em models: slices by lifecycle status, driftSignal breakdown, invariant coverage totals (with --tests), open issue markers + unchecked Open Questions, and last-conformance commits-behind-HEAD (MIL-163, see docs/cli.md)
|
|
110
132
|
em status <files> --tests <dir> # directory to scan for INV-* test citations — enables invariant coverage totals
|
|
@@ -116,6 +138,10 @@ em status <files> -o, --out <path> # write output to
|
|
|
116
138
|
em freshness <file> # standalone freshness signal for one model's conformance record (MIL-164): "last conformed <rev> — N commits and M slice-PRs behind HEAD", computed from the same conform-scope machinery `em status`'s conformance clause uses — for when you want just this fact, no full state-of-the-system rollup (see docs/cli.md)
|
|
117
139
|
em freshness <file> --repo <path> # git repo to compute behind-HEAD in (default: the model's own directory)
|
|
118
140
|
em freshness <file> --json # print a JSON document instead of the text line
|
|
141
|
+
em metrics <file> # the pilot metrics named in advance by the register, computed from git history alone (MIL-170): ratification turnaround (reviewed -> ratified -> implemented), conform-cycle cadence + finding counts, and status-vs-reality disagreement over time — plus a fourth, reported as not computable from history (see docs/usage-data.md). `<file>` is an anchor .em file, used only to locate slices/, conformance/, and .event-modeling.md relative to it — same convention as em ledger; never parsed or compiled
|
|
142
|
+
em metrics <file> --from <rev> # baseline revision
|
|
143
|
+
em metrics <file> --to <rev> # compare revision (default: HEAD)
|
|
144
|
+
em metrics <file> --json # print a JSON document instead of the text report (see docs/cli.md)
|
|
119
145
|
em query consumers <files> # views/reactions consuming an event, plus their slices
|
|
120
146
|
em query consumers <files> --event <ref-or-name> # the event's export ref or display name
|
|
121
147
|
em query consumers <files> --json # print a JSON document instead of the text report
|
|
@@ -152,7 +178,7 @@ em query path <files> --json # print a JSON doc
|
|
|
152
178
|
em system <manifest> # verify a seam manifest (system.yaml) against its models' exports — every `public` event/view bound to a reaction in another model, the cross-model half of "both ends of a flow" (MIL-194, see docs/cli.md)
|
|
153
179
|
em system <manifest> --json # print a JSON document instead of the text report (see docs/cli.md)
|
|
154
180
|
em contract # print the packaged implementation contract (reference/implement.md) to stdout — the agent-neutral discovery path for any agent that can run a shell, not just Claude Code (MIL-129); see docs/cli.md
|
|
155
|
-
em mcp # start an MCP (Model Context Protocol) server over stdio (MIL-21) — a structured, agent-facing alternative to shelling out to `em`;
|
|
181
|
+
em mcp # start an MCP (Model Context Protocol) server over stdio (MIL-21) — a structured, agent-facing alternative to shelling out to `em`; every tool mirrors a CLI `--json` surface byte-for-byte. docs/mcp.md isn't vendored into the skill bundle — for the handshake and the full, current tool table (the list changes as commands gain MCP parity, so it's not repeated here — MIL-187) see https://github.com/milehimikey/em/blob/main/docs/mcp.md. Equivalent to running the `em-mcp` bin directly
|
|
156
182
|
em skill install # copy the event-modeling skill bundle into .claude/skills/ (event-modeling, event-modeling-discover/-design/-implement/-conform/-review, event-modeling-shared); across a structural bundle change (e.g. the MIL-157 split of the old single event-modeling/ directory into this six-directory bundle), `em skill sync` is the migration path — --force now performs the same reconcile (MIL-180)
|
|
157
183
|
em skill install -f, --force # overwrite an existing installation, reconciling added/updated/removed files within the bundle's own managed directories the same way `em skill sync` does — never touching an unrelated sibling skill (MIL-180)
|
|
158
184
|
em skill install --no-agents-md # skip writing/updating the AGENTS.md agent-contract section (on by default, MIL-129)
|
|
@@ -164,6 +190,10 @@ em ci init <model> # install .github/
|
|
|
164
190
|
em ci init <model> --tests <dir> # test directory the coverage/status steps scan for INV-* citations
|
|
165
191
|
em ci init <model> -f, --force # replace an existing workflow file that has no GENERATED markers
|
|
166
192
|
em ci init <model> --check # verify both files match the current preset; exit non-zero on drift without writing (CI)
|
|
193
|
+
em upgrade <file> # bring a model repo authored under an older em (1.6 forward) up to the installed version: an ordered list of mechanical steps (skill bundle, reaction shape, state-file bullets, generated CI blocks, constitution scaffold) plus a human list of things no command can safely decide by itself (MIL-219, see docs/upgrading.md). Dry-run by default; --apply makes one git commit per applicable step, refusing on a dirty working tree
|
|
194
|
+
em upgrade <file> --apply # apply every applicable mechanical step, one git commit each, then a final `Em version:` commit
|
|
195
|
+
em upgrade <file> --check # exit non-zero only on a hard incompatibility (unparseable state file, an un-migratable .em shape) — writes nothing; what CI runs
|
|
196
|
+
em upgrade <file> --json # print a JSON document instead of text (dry-run/--check only, never with --apply)
|
|
167
197
|
```
|
|
168
198
|
<!-- GENERATED:cli:end -->
|
|
169
199
|
|
|
@@ -224,7 +254,11 @@ type Name { field: Type, ... } # named structured type, reusable from any f
|
|
|
224
254
|
connected to one another — continuity is implied by the shared name, and the events reaching each
|
|
225
255
|
instance are what show the view changing. `again` with no earlier declaration is a validation error.
|
|
226
256
|
Use `again` (not a plain repeated `view` name) whenever the view is referenced by a
|
|
227
|
-
`from`/`arrow` — plain repeats are only warning-free while unreferenced.
|
|
257
|
+
`from`/`arrow` — plain repeats are only warning-free while unreferenced. A later instance is
|
|
258
|
+
also a **continuation** for the doc lifecycle (MIL-208): it stays a slice on the timeline but
|
|
259
|
+
is not a spec unit — no doc, no status, no ratification, no PR of its own; the originating
|
|
260
|
+
slice's doc carries its behavior and `em export`'s `alsoReads` carries the union of events it
|
|
261
|
+
reads. See `slice-doc-schema.md`'s "Continuations" section for the full contract.
|
|
228
262
|
- **`loops-to "View"`** (events only): marks an event as re-feeding an earlier read model — a
|
|
229
263
|
poll/retry loop where a later fact must re-trigger an automation that already ran (a lapsed
|
|
230
264
|
reservation re-notifying the next person waiting in line, and similar re-triggers). Written
|
|
@@ -265,6 +299,14 @@ type Name { field: Type, ... } # named structured type, reusable from any f
|
|
|
265
299
|
this model). `em export` carries it as `public: true`/`false`; `em diff` reports a flip as
|
|
266
300
|
`event marked public`/`event unmarked public` (the entry cites the element's kind, so a
|
|
267
301
|
view flip reads `view "X"`); `em validate --list-public` audits the whole public surface.
|
|
302
|
+
**Exposure of a read model (MIL-215) is three cases, no dedicated keyword:** a person/client
|
|
303
|
+
reads it → draw the `ui` that reads it (ships the endpoint); another model/system reads it →
|
|
304
|
+
`public` (a cross-model contract, verified by `em system <manifest>`, not `em validate`); only
|
|
305
|
+
an automation reads it → nothing — internal by design, the read a reaction is required to
|
|
306
|
+
make, not an endpoint. `em validate --list-public` flags a `public` view with no `ui`/reaction
|
|
307
|
+
reading it anywhere in this model as an audit note ("no in-model reader"), not a warning — a
|
|
308
|
+
cross-model `public` view's reader legitimately lives outside this file (see "`em validate`
|
|
309
|
+
rules" below).
|
|
268
310
|
- **`tag`** (events only): declares a DCB (Dynamic Consistency Boundary) tag key. Three forms:
|
|
269
311
|
a trailing `tag` on a field line inside the event's `{ … }` block (`priceId: UUID tag`, or
|
|
270
312
|
typeless `priceId tag`) — an identity tag, key defaults to the field's own name; a bare field
|
|
@@ -516,6 +558,11 @@ slice "Read Quote — created" {
|
|
|
516
558
|
Keep the read model adjacent to its event, and keep a sub-flow that detours into another context
|
|
517
559
|
together rather than parking it at the end of the model.
|
|
518
560
|
|
|
561
|
+
What this means for whoever builds a slice, not just whoever draws it: a `ui` trigger or
|
|
562
|
+
consumer is an obligation to ship an endpoint, no `ui` means internal-only, and `public` marks
|
|
563
|
+
the published integration surface — see `reference/implement.md`'s "Interface obligations"
|
|
564
|
+
paragraph in the `event-modeling-implement` skill (§2).
|
|
565
|
+
|
|
519
566
|
### Reaction wiring — no positional gotcha
|
|
520
567
|
|
|
521
568
|
A reaction's command is inferred from **same-slice presence**, exactly like `ui -> command`: put
|
|
@@ -646,6 +693,7 @@ not the prose above has caught up yet. `--slice-ready <key>`-only codes are excl
|
|
|
646
693
|
| `both-ends-of-a-flow/ui-unbacked` | warning | `ui` with no read model or command | Add a `view` it displays, or the command it triggers. |
|
|
647
694
|
| `both-ends-of-a-flow/view-unconsumed` | warning | Read model with no consumer | Add a `ui` or reaction that consumes it, or drop this instance. |
|
|
648
695
|
| `connection-legality/illegal-pair` | error | Illegal connection | Only ui→command→event→view→ui and view→reaction→command are legal — the message names the missing step. |
|
|
696
|
+
| `continuation-has-own-doc` | warning | Continuation slice has its own doc | Fold this doc's scenarios into slices/<originating-key>.md and delete it; a later `view X again` instance is documented by the view's originating slice. |
|
|
649
697
|
| `cross-model-slice-doc-collision` | warning | Colliding slice doc path across models | Give each model its own directory (see docs/cli.md, "Multi-model projects"). |
|
|
650
698
|
| `dangling-public-event` | warning | Public event/view no seam consumes | Declare the seam that reads it, or drop `public` if nothing outside the model does. |
|
|
651
699
|
| `derived-from-unresolved` | error | `derived from` names an unknown event | Name one of the view's actual sources, or drop the traced event from `derived from`. |
|
|
@@ -670,6 +718,7 @@ not the prose above has caught up yet. `--slice-ready <key>`-only codes are excl
|
|
|
670
718
|
| `lineage-version-impossible` | error | Impossible lineage version | Fix the referenced version, or ratify the target slice first. |
|
|
671
719
|
| `loops-to-forward` | error | `loops-to` target not earlier on the timeline | Point `loops-to` at an earlier view, or use `from` on a later `view … again` instance instead. |
|
|
672
720
|
| `loops-to-unresolved` | error | `loops-to` target unresolved | Name a view that exists, or declare it before this event. |
|
|
721
|
+
| `model-version-stale` | warning | Model version stale | Run `em model version bump` to record the current model content/slice-version vector. |
|
|
673
722
|
| `note-binding-dangling` | warning | Dangling cross-slice note | Create the doc at that path, or fix/remove the note. |
|
|
674
723
|
| `note-binding-extra` | warning | Extra doc-binding note, ignored | Remove the note, or point it at the slice's actual bound doc. |
|
|
675
724
|
| `note-binding-unratified` | warning | Unratified cross-slice note | Add `covers: <this-slice-key>` to that doc's frontmatter, or correct the note's path. |
|
|
@@ -77,7 +77,17 @@ right here as `reference/slice-doc-schema.md` (kept in sync with the em repo's
|
|
|
77
77
|
|
|
78
78
|
1. Check the tool: `em --version`. If missing, tell the user to run `npm i -g @milehimikey/em`
|
|
79
79
|
and stop until installed.
|
|
80
|
-
2.
|
|
80
|
+
2. Check this vendored skill bundle's own currency (MIL-219): read this file's `em-version:`
|
|
81
|
+
frontmatter stamp (or any sibling skill's SKILL.md — they're stamped together) and compare it
|
|
82
|
+
to `em --version` from step 1. **If the installed em is ahead by a minor version or more
|
|
83
|
+
(1.9.x → 1.11.x, or any major bump), STOP** — don't proceed with discover/model/slice/
|
|
84
|
+
implement/conform/review work on this stamp. Tell the user the vendored bundle is stale and to
|
|
85
|
+
run `em skill sync` (refresh the bundle only) or `em upgrade` (the bundle plus the model
|
|
86
|
+
repo's other mechanical migrations, docs/upgrading.md) before continuing. A patch-only gap
|
|
87
|
+
(1.11.2 → 1.11.4) is never worth stopping over — proceed normally. This matters because a
|
|
88
|
+
stale bundle silently follows old rules: an agent reading superseded preconditions/gates
|
|
89
|
+
can hand back work that looks right by last week's contract and wrong by this week's.
|
|
90
|
+
3. Locate the model. Look for an existing `<dir>/.event-modeling.md` and `*.em` in the working
|
|
81
91
|
directory, or — for a multi-model project laid out per the convention below — one level down
|
|
82
92
|
inside a `models/` subfolder (each model gets its own `models/<slug>/` directory; check each
|
|
83
93
|
candidate for its own `.event-modeling.md`/`*.em` pair). If found, run `em state read <dir>`
|
|
@@ -85,12 +95,12 @@ right here as `reference/slice-doc-schema.md` (kept in sync with the em repo's
|
|
|
85
95
|
conformance, last review) as JSON — don't parse the bullets by hand. If not, and the phase
|
|
86
96
|
needs one, ask the user for the model name and where to create it (a lone model goes at the
|
|
87
97
|
project root; one of several goes under `models/`, per "Multi-model projects" below).
|
|
88
|
-
|
|
98
|
+
4. If you're not sure which phase applies, or the user gave no phase, use `em state read <dir>`'s
|
|
89
99
|
`phase`/`step` to resume the recorded phase/step — or invoke the `event-modeling` skill, which
|
|
90
100
|
does exactly this and routes to the right skill. If no model exists, propose starting
|
|
91
101
|
`discover` (greenfield, `event-modeling-discover`) or `extract` (modeling an existing system,
|
|
92
102
|
also `event-modeling-discover`).
|
|
93
|
-
|
|
103
|
+
5. Populate the state file's Participants section at session start. For a live workshop, ask for
|
|
94
104
|
a single human proxy to relay questions to the room, and attribute every answer/decision in
|
|
95
105
|
the Decisions log to a named participant.
|
|
96
106
|
|
|
@@ -69,6 +69,9 @@ to decide `frontmatter-invalid` without re-deriving frontmatter-shape rules of i
|
|
|
69
69
|
| `ratifiedOn` | string | `YYYY-MM-DD` | written only by `em slice ratify` (MIL-165); joined into `em export`'s `slice.doc.ratifiedOn` (schema `1.8`) |
|
|
70
70
|
| `owner` | string | free text (typically a person or team name) | hand-filled — no `em` command writes it; joined into `em export`'s `slice.doc.owner` (schema `1.9`, MIL-171), `em slice index`'s Owner column, and `em status`'s per-slice `owners[]` |
|
|
71
71
|
| `tracking` | string | free text (typically an external ticket/issue URL) | hand-filled — no `em` command writes it; joined into `em export`'s `slice.doc.tracking` (schema `1.9`, MIL-171) and `em slice index`'s Tracking column. This is the exact field `em-tracker-bridge` reads to find the ticket mirroring this slice — `em` only stores and displays it, it never talks to a tracker itself |
|
|
72
|
+
| `conformedVersion` | integer | positive integer | written only by `em slice conform` (MIL-214 — see [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-slice-conform-file-slice-key---at-rev)): this slice's `version:` at the time a conform sweep last certified it. Joined into `em export`'s `slice.doc.conformedVersion` (schema `1.13`); paired with `version` to compute `slice.doc.driftSignal`'s `"uncertified"` case |
|
|
73
|
+
| `conformedAt` | string | free text (a target-repo revision, NOT a `<slice-key>@v<N>` lineage ref) | written only by `em slice conform` (MIL-214): the revision that certification sweep diffed against. Joined into `em export`'s `slice.doc.conformedAt` (schema `1.13`) and `em slice index`'s Conformed column |
|
|
74
|
+
| `conformedOn` | string | `YYYY-MM-DD` | written only by `em slice conform` (MIL-214). Joined into `em export`'s `slice.doc.conformedOn` (schema `1.13`) |
|
|
72
75
|
|
|
73
76
|
Five keys — `schemaVersion`/`pattern`/`swimlane`/`status`/`version` — are what
|
|
74
77
|
`hasUsableFrontmatter()` requires: a doc omitting any of them is `frontmatter-invalid` to
|
|
@@ -89,6 +92,7 @@ convention, not parser-enforced.
|
|
|
89
92
|
| `reviewedBy`, `reviewedOn` | optional in every state — present once `em slice review` (MIL-201) has run at least once; a doc that never went through the review gate, or was hand-flipped to `reviewed`, simply omits both. `em slice ratify` never clears them; `em slice reratify` does (they describe the version that shipped) |
|
|
90
93
|
| `ratifiedBy`, `ratifiedOn` | optional in every state — present once `em slice ratify` (MIL-165) has run at least once; a doc predating this feature, or ratified by hand, simply omits both |
|
|
91
94
|
| `owner`, `tracking` | optional in every state — hand-filled whenever a team wants a who-holds-this / external-tracker link; most docs never carry either (MIL-171) |
|
|
95
|
+
| `conformedVersion`, `conformedAt`, `conformedOn` | optional in every state — present once `em slice conform` (MIL-214) has run at least once for the CURRENT version; a doc that's never been through a conform sweep, or whose `version` has since bumped past what was certified, simply has none of the three (or a stale triple — see `driftSignal`'s `uncertified` case below) |
|
|
92
96
|
|
|
93
97
|
`em export`'s slice-doc join (MIL-91) is the first `em` command to mechanically check the
|
|
94
98
|
required row above: a bound doc missing any of `schemaVersion`/`pattern`/`swimlane`/`status`/
|
|
@@ -101,6 +105,32 @@ No `em` command fails a build over this table. `em validate`'s frontmatter-coher
|
|
|
101
105
|
(never fails) on the one combination checkable without git history: `status: implemented` with
|
|
102
106
|
no `implementedIn` link at all.
|
|
103
107
|
|
|
108
|
+
## Stub docs
|
|
109
|
+
|
|
110
|
+
`em slice new --stub` and `em slice stub-all` (MIL-184, ruled 2026-09-08 on GH #128 — see that
|
|
111
|
+
issue for the fuller design rationale) write a **stub**: the exact same 5 required-at-`status:
|
|
112
|
+
draft` frontmatter keys above, but a one-line placeholder body (`_Stub — deepen with the slice
|
|
113
|
+
phase (see slice-doc-schema.md)._`) instead of the diagram-image stub and every judgment section
|
|
114
|
+
(Intent, Command, Scenarios, Open Questions, …) a full slice doc eventually carries.
|
|
115
|
+
|
|
116
|
+
A stub is not a lesser doc, frontmatter-wise — it's a real doc with a real `status`, parsed and
|
|
117
|
+
joined by `em export`/`em catalog`/`em status`/`em slice index` exactly like a fully-written one,
|
|
118
|
+
because it's the same frontmatter dialect. The doc stays the single source of truth for
|
|
119
|
+
`status`; a stub is just the cheapest possible way to give a slice one before anyone's ready to
|
|
120
|
+
write the real spec.
|
|
121
|
+
|
|
122
|
+
**A stub CAN pass `em validate --slice-ready`.** That gate checks four things (`computeSliceReadyGates`,
|
|
123
|
+
[validation.md#slice-readiness](https://github.com/milehimikey/em/blob/main/docs/validation.md#slice-readiness)): a doc is bound, its frontmatter
|
|
124
|
+
is usable, `status` is `ready-to-implement`, and its Open Questions count has none unchecked. A
|
|
125
|
+
stub with no `## Open Questions` section at all has `openQuestionsTotal: 0` (see
|
|
126
|
+
[Open Questions section: lifecycle](#open-questions-section-lifecycle) below) — zero unchecked is
|
|
127
|
+
vacuously true — so a stub escalated to `ready-to-implement` (`em slice stub-all --status
|
|
128
|
+
ready-to-implement --by <name>`) passes cleanly. The readiness gate is frontmatter-plus-checkbox-
|
|
129
|
+
count only; it has no opinion about whether Intent/Command/Scenarios/Invariants were ever
|
|
130
|
+
written. Demanding that content is the `slice` phase's (and, for a live walkthrough, the review
|
|
131
|
+
skill's) job, not a machine gate's — see `../.claude/skills/event-modeling-design/SKILL.md` and
|
|
132
|
+
`../.claude/skills/event-modeling-review/SKILL.md`.
|
|
133
|
+
|
|
104
134
|
## Lineage: grammar and cardinality
|
|
105
135
|
|
|
106
136
|
Grammar: `<slice-key>@v<N>` — `<slice-key>` is the referenced slice's kebab-case filename stem
|
|
@@ -180,6 +210,12 @@ reads a bound doc's canonical fields (`em export`'s `slice.doc`, `em validate --
|
|
|
180
210
|
`implementedIn`/lineage/Open Questions, not the covered slice's own (nonexistent) file. A doc
|
|
181
211
|
covers its own canonical slice key implicitly — `covers` never needs to list it.
|
|
182
212
|
|
|
213
|
+
`em catalog` (MIL-137) is one such consumer, via the same filename+frontmatter `covers:` scan
|
|
214
|
+
(`src/catalog/coverage.ts`), never the `note` clause itself: a covered slice's detail page shows
|
|
215
|
+
the covering doc's Status, but a "Documented as part of <covering slice>" banner instead
|
|
216
|
+
of the covering doc's body — linking to the covering slice's own catalog page rather than
|
|
217
|
+
inlining content authored under a different slice's name.
|
|
218
|
+
|
|
183
219
|
`covers` is a plain list of slice keys (`<slice-key>`, e.g. `detect-unpaid-orders`), **not** the
|
|
184
220
|
`<slice-key>@v<N>` ref grammar the lineage keys use above: coverage is a standing "this doc also
|
|
185
221
|
serves that slice" declaration, with no version component — unlike lineage, which records a
|
|
@@ -195,6 +231,39 @@ the mismatch, as its own separate rule (MIL-126) — see
|
|
|
195
231
|
that just doesn't ratify (`covers` doesn't list this slice back), and an extra note doing nothing
|
|
196
232
|
in a slice that's already bound elsewhere, each get their own diagnostic there.
|
|
197
233
|
|
|
234
|
+
## Continuations
|
|
235
|
+
|
|
236
|
+
Since `em` 1.12.0 (MIL-208): a `view X again` instance is a **continuation** of the slice
|
|
237
|
+
holding `X`'s first (originating) declaration — one read model, fed by more than one event over
|
|
238
|
+
the timeline — not a spec unit of its own. Unlike `covers` above, this is fully automatic and
|
|
239
|
+
structural: no frontmatter, no `note`, nothing to author. A slice is a continuation iff every
|
|
240
|
+
non-`ui` element it declares is a `view` with `again === true`; the doc join resolves it
|
|
241
|
+
straight through to the originating slice's own doc, exactly the way a ratified `covers:`
|
|
242
|
+
binding resolves a covered slice — same `doc.found`/`status`/`driftSignal`, plus a
|
|
243
|
+
`continuationOf: <originating-key>` field naming why. `em export`, `em status`, `em coverage`,
|
|
244
|
+
`em slice index`, `em catalog`, and the render pipeline's Slice Status legend all resolve a
|
|
245
|
+
continuation slice this way; `em slice ratify`/`review`/`reratify`/`mark-implemented` and
|
|
246
|
+
`em slice new --wire` refuse on one outright, naming the originating slice to act on instead —
|
|
247
|
+
a continuation slice has no status/ratification of its own to flip.
|
|
248
|
+
|
|
249
|
+
The originating slice's own `em export` object also gains `alsoReads: [{ event, atSlice }]` —
|
|
250
|
+
the union of events every later `again` instance of that view reads via `from`, in timeline
|
|
251
|
+
order — so implementing the read model from one export never means walking every `again`
|
|
252
|
+
slice's doc by hand to assemble the full event list.
|
|
253
|
+
|
|
254
|
+
**Authoring convention:** a continuation's behavior belongs in the originating doc's own
|
|
255
|
+
`## Scenarios (Given / When / Then)` section — one scenario per event a later `again` instance
|
|
256
|
+
feeds — rather than in a doc of its own; no new frontmatter is needed to record it.
|
|
257
|
+
|
|
258
|
+
**Legacy own doc wins.** A slice that would otherwise be a continuation but still carries its
|
|
259
|
+
own doc — a `note "slices/<again-key>.md"` binding it, or a stray `slices/<again-key>.md` file
|
|
260
|
+
left over from before this rule existed — keeps today's per-instance behavior unchanged: its own
|
|
261
|
+
doc, its own status, its own ratification. `em validate`'s `continuation-has-own-doc` warning
|
|
262
|
+
(see [validation.md](https://github.com/milehimikey/em/blob/main/docs/validation.md)) flags it either way, so an author can fold that doc's
|
|
263
|
+
scenarios into `slices/<originating-key>.md` and delete it. This is the migration path — an
|
|
264
|
+
existing model with per-`again`-instance docs keeps working exactly as before until each one is
|
|
265
|
+
folded in.
|
|
266
|
+
|
|
198
267
|
## Delta section: grammar and lifecycle
|
|
199
268
|
|
|
200
269
|
`## Delta` is the body section that pairs with a re-ratification (see "`status` under
|
|
@@ -31,7 +31,14 @@ Replace bracketed placeholders; delete guidance comments before finishing.
|
|
|
31
31
|
## Findings
|
|
32
32
|
|
|
33
33
|
<!-- One subsection per finding. Group however reads clearest (by slice, or by surface) but keep
|
|
34
|
-
every field below for every finding. Order doesn't matter; classification does.
|
|
34
|
+
every field below for every finding. Order doesn't matter; classification does.
|
|
35
|
+
|
|
36
|
+
MIL-214: this section's structured twin is `conformance/{{YYYY-MM-DD}}-findings.json`,
|
|
37
|
+
written ALONGSIDE this report (not after it) — one JSON entry per `### n.` finding below,
|
|
38
|
+
`id` matching `{{n}}`. See reference/conform.md step 5 for the exact shape and the write-then-
|
|
39
|
+
`em conform-findings check`-it discipline. A later `em conform-supersede --locus --by` call
|
|
40
|
+
records the ruling on both the JSON (locus/resolvedBy/resolvedOn) and this report's banner
|
|
41
|
+
in one call. -->
|
|
35
42
|
|
|
36
43
|
### {{n}}. {{Short finding title}}
|
|
37
44
|
|
|
@@ -46,6 +46,9 @@ technical choice" an implementing agent would otherwise make alone.
|
|
|
46
46
|
- **Architectural pattern:** {{e.g. event-sourced CQRS with vertical slices; layered service over
|
|
47
47
|
a relational store; functional core / imperative shell}}
|
|
48
48
|
- **Where a slice's code lives:** {{one package per slice, per context, ...}}
|
|
49
|
+
- **Interface conventions:** {{resource style — REST/RPC/GraphQL, etc.; error/rejection mapping;
|
|
50
|
+
versioning; auth at the edge — the shape every `ui`-triggered command or `ui`-consumed view's
|
|
51
|
+
endpoint follows, decided once here rather than invented per slice}}
|
|
49
52
|
|
|
50
53
|
Routing — which implementation skill or approach each of the four slice patterns uses:
|
|
51
54
|
|
|
@@ -105,7 +108,11 @@ it is silent, these apply.
|
|
|
105
108
|
- **Reviewers:** {{who — a team, a CODEOWNERS rule, the slice's ratifier}}
|
|
106
109
|
- **What blocks a merge:** {{e.g. a failing suite, an uncovered invariant, a gap that belongs back
|
|
107
110
|
at the model}}
|
|
108
|
-
- **Branch / commit conventions:** {{...}}
|
|
111
|
+
- **Branch / commit conventions:** {{...}} — name only branch naming and commit-message style
|
|
112
|
+
here. **One slice doc = one PR is the implement contract's rule, not this document's to
|
|
113
|
+
amend** — a `covers:` doc ships as one PR for both keys; a read model is one doc, so a later
|
|
114
|
+
`again` instance is a continuation of the doc that first declared it, not a PR of its own. See
|
|
115
|
+
the agent guide's §5/§10.
|
|
109
116
|
- **At merge:** run `em slice mark-implemented <model>.em <slice-key> <pr-url>` — the one edit an
|
|
110
117
|
implementing agent makes to a ratified slice doc, run by {{the PR author | CI}}. Never bump
|
|
111
118
|
`version:`; that moves only when a delta is ratified.
|
|
@@ -7,10 +7,13 @@ Keep it current at the end of every working session.
|
|
|
7
7
|
# Event Modeling Progress — {{Model Name}}
|
|
8
8
|
|
|
9
9
|
- **Model file:** `{{model-name}}.em`
|
|
10
|
+
- **Em version:** {{X.Y.Z}}
|
|
10
11
|
- **Current phase:** {{discover | extract | model | slice | implement | conform | review | validate}}
|
|
11
12
|
- **Current step:** {{1–7, see methodology; or extraction round R1–R7}}
|
|
12
13
|
- **Last updated:** {{YYYY-MM-DD}}
|
|
13
14
|
- **Last conformance:** {{YYYY-MM-DD @ <target-repo revision> — report: conformance/<date>-report.md | never}}
|
|
15
|
+
- **Model version:** {{N | none}}
|
|
16
|
+
- **Certified:** {{v<N> @ <target-repo revision> (YYYY-MM-DD) | never}}
|
|
14
17
|
- **Last stakeholder review:** {{YYYY-MM-DD — attendees: see Participants | never}}
|
|
15
18
|
|
|
16
19
|
## Session inputs
|
package/README.md
CHANGED
|
@@ -118,6 +118,7 @@ built this way.
|
|
|
118
118
|
| [docs/cli.md](docs/cli.md) | Every command and flag |
|
|
119
119
|
| [docs/validation.md](docs/validation.md) | Every rule `em validate` checks, and the fixes |
|
|
120
120
|
| [docs/ci.md](docs/ci.md) | Copy-paste CI recipes: validate `.em` changes, run conformance on a schedule |
|
|
121
|
+
| [docs/upgrading.md](docs/upgrading.md) | Bring a model repo forward across em releases: `em upgrade`, release by release |
|
|
121
122
|
| [docs/timeline.md](docs/timeline.md) | The Two Laws of the Timeline |
|
|
122
123
|
| [docs/ai-workflow.md](docs/ai-workflow.md) | The Claude Code skill: install, phases, artifacts |
|
|
123
124
|
| [docs/dependencies.md](docs/dependencies.md) | What's bundled vs. what needs a system install |
|
package/dist/catalog/build.js
CHANGED
|
@@ -13,10 +13,12 @@
|
|
|
13
13
|
import { existsSync, readFileSync } from "node:fs";
|
|
14
14
|
import { copyFile, mkdir, writeFile } from "node:fs/promises";
|
|
15
15
|
import { basename, dirname, extname, join } from "node:path";
|
|
16
|
+
import { continuationOf } from "../model/continuation.js";
|
|
16
17
|
import { layoutDot, composeSvg, writeRendered } from "../render/render.js";
|
|
17
18
|
import { buildSliceDiagram } from "../render/sliceDiagram.js";
|
|
18
19
|
import { dedupe, kebabSlug } from "../util/slug.js";
|
|
19
20
|
import { classifySlicePattern } from "./classify.js";
|
|
21
|
+
import { readCoverageDocs } from "./coverage.js";
|
|
20
22
|
import { detectSliceDocCollisions } from "./modelCollisionValidate.js";
|
|
21
23
|
import { parseSliceDoc } from "./sliceDoc.js";
|
|
22
24
|
import { renderIndexPage, renderSlicePage } from "./pages.js";
|
|
@@ -51,6 +53,11 @@ export async function buildCatalog(inputs, opts) {
|
|
|
51
53
|
if (refs.diagnostics.length > 0)
|
|
52
54
|
diagnostics.push({ file, diagnostics: refs.diagnostics });
|
|
53
55
|
const sliceSummaries = [];
|
|
56
|
+
// MIL-137: built lazily, only if some slice below actually lacks its own doc — same
|
|
57
|
+
// shared scan (src/catalog/coverage.ts) the render pipeline's Slice Status legend uses
|
|
58
|
+
// (src/render/sliceStatus.ts), so a covered slice never resolves to a different doc
|
|
59
|
+
// depending on which command asked.
|
|
60
|
+
let coverageDocs = null;
|
|
54
61
|
for (let i = 0; i < model.slices.length; i++) {
|
|
55
62
|
const slice = model.slices[i];
|
|
56
63
|
const sliceKey = refs.sliceKeys[i];
|
|
@@ -63,7 +70,40 @@ export async function buildCatalog(inputs, opts) {
|
|
|
63
70
|
// instead of silently rendering the first slice's doc content on both pages.
|
|
64
71
|
const docRelPath = join("slices", `${sliceKey}.md`);
|
|
65
72
|
const docPath = join(dirname(file), docRelPath);
|
|
66
|
-
const
|
|
73
|
+
const ownDoc = existsSync(docPath) ? parseSliceDoc(readFileSync(docPath, "utf8")) : null;
|
|
74
|
+
// MIL-137: no own doc -> fall back to a sibling doc that ratifies coverage of this slice
|
|
75
|
+
// (MIL-121 `covers:`). The covering doc's status/pattern act as this slice's own for the
|
|
76
|
+
// index Status column and this page's header badge (same "one doc, one status" rule the
|
|
77
|
+
// render pipeline's Slice Status legend already applies), but its BODY is never inlined —
|
|
78
|
+
// the detail page shows a "documented as part of" banner linking to the covering slice's
|
|
79
|
+
// own page instead, never the covering doc's content rendered under a different slice's
|
|
80
|
+
// name.
|
|
81
|
+
let doc = ownDoc;
|
|
82
|
+
let coveredBy = null;
|
|
83
|
+
if (!ownDoc) {
|
|
84
|
+
coverageDocs ??= readCoverageDocs(join(dirname(file), "slices"));
|
|
85
|
+
const covering = coverageDocs.get(sliceKey);
|
|
86
|
+
if (covering) {
|
|
87
|
+
doc = covering.doc;
|
|
88
|
+
const coveringIndex = refs.sliceKeys.indexOf(covering.key);
|
|
89
|
+
coveredBy = { key: covering.key, name: coveringIndex >= 0 ? model.slices[coveringIndex].name : covering.key, kind: "covers" };
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// MIL-208: still no doc — check whether this slice is a CONTINUATION (an again-view-
|
|
93
|
+
// only slice) of another slice's own file, filename-convention resolution's own
|
|
94
|
+
// fallback (mirrors render/sliceStatus.ts's readSliceDocs). Checked last, after both
|
|
95
|
+
// the own-file and MIL-121 covers: lookups have already come up empty.
|
|
96
|
+
const continuation = continuationOf(model, refs, i);
|
|
97
|
+
if (continuation) {
|
|
98
|
+
const originatingPath = join(dirname(file), "slices", `${continuation.sliceKey}.md`);
|
|
99
|
+
if (existsSync(originatingPath)) {
|
|
100
|
+
doc = parseSliceDoc(readFileSync(originatingPath, "utf8"));
|
|
101
|
+
const originatingSlice = model.slices[continuation.sliceIndex];
|
|
102
|
+
coveredBy = { key: continuation.sliceKey, name: originatingSlice.name, kind: "continuation" };
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
67
107
|
// Same sibling-file convention as the doc lookup above, one extension over: a
|
|
68
108
|
// slice diagram authored by `em render --slice` (per the event-modeling skill)
|
|
69
109
|
// is copied in as-is so the catalog stays self-contained; otherwise built
|
|
@@ -103,6 +143,7 @@ export async function buildCatalog(inputs, opts) {
|
|
|
103
143
|
pattern,
|
|
104
144
|
elementRefs,
|
|
105
145
|
doc,
|
|
146
|
+
coveredBy,
|
|
106
147
|
docExpectedPath: docRelPath,
|
|
107
148
|
});
|
|
108
149
|
await writeFile(join(slicesDir, `${sliceKey}.html`), page, "utf8");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/catalog/build.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,0EAA0E;AAC1E,4EAA4E;AAC5E,EAAE;AACF,cAAc;AACd,iBAAiB;AACjB,mBAAmB;AACnB,8BAA8B;AAC9B,gBAAgB;AAChB,2BAA2B;AAC3B,2FAA2F;AAE3F,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/catalog/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SliceDoc } from "./sliceDoc.js";
|
|
2
|
+
/** A covering doc, plus the covering slice's OWN key (its `slices/<key>.md` filename stem,
|
|
3
|
+
* stripped of the extension). Callers that need to link to or name the covering slice itself
|
|
4
|
+
* (`em catalog`'s "documented as part of" banner) get it here rather than re-deriving "which
|
|
5
|
+
* slice does this doc actually belong to" from `doc`, which has no notion of its own key. */
|
|
6
|
+
export interface CoveringDoc {
|
|
7
|
+
doc: SliceDoc;
|
|
8
|
+
key: string;
|
|
9
|
+
}
|
|
10
|
+
/** Scans every `slices/*.md` file (sorted, for deterministic first-wins on an overlapping
|
|
11
|
+
* `covers:` claim) and maps each covered slice key to the doc — and that doc's own key — that
|
|
12
|
+
* covers it. Directory-scan, not the single-file existsSync check every other doc lookup in em
|
|
13
|
+
* uses — the one precedent for it is `em ledger`'s (src/cli/ledgerCheck.ts) own
|
|
14
|
+
* `readdirSync(slicesDir)` sweep. */
|
|
15
|
+
export declare function readCoverageDocs(slicesDir: string): Map<string, CoveringDoc>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Shared MIL-121 "covered by" doc-discovery: scans `slices/*.md` for a frontmatter `covers:`
|
|
3
|
+
// entry naming a slice that has no doc of its own. Every consumer that needs this fallback —
|
|
4
|
+
// the render pipeline's Slice Status legend (src/render/sliceStatus.ts) and `em catalog`'s
|
|
5
|
+
// detail pages (src/catalog/build.ts, MIL-137) — shares this one scan, so a covered slice never
|
|
6
|
+
// resolves to a different doc (or a different notion of which slice covers it) depending on
|
|
7
|
+
// which command asked. Filename+frontmatter discovery only: never reads Element.note — that
|
|
8
|
+
// cross-note is docJoin.ts's concern (`em export`'s doc join, `em validate --slice-ready`), not
|
|
9
|
+
// this module's; test/catalog.e2e.test.ts pins "never reads note" as an invariant for `em
|
|
10
|
+
// catalog`, and this module is exactly as blind to it.
|
|
11
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { parseSliceDoc } from "./sliceDoc.js";
|
|
14
|
+
/** Scans every `slices/*.md` file (sorted, for deterministic first-wins on an overlapping
|
|
15
|
+
* `covers:` claim) and maps each covered slice key to the doc — and that doc's own key — that
|
|
16
|
+
* covers it. Directory-scan, not the single-file existsSync check every other doc lookup in em
|
|
17
|
+
* uses — the one precedent for it is `em ledger`'s (src/cli/ledgerCheck.ts) own
|
|
18
|
+
* `readdirSync(slicesDir)` sweep. */
|
|
19
|
+
export function readCoverageDocs(slicesDir) {
|
|
20
|
+
const coverage = new Map();
|
|
21
|
+
if (!existsSync(slicesDir))
|
|
22
|
+
return coverage;
|
|
23
|
+
const files = readdirSync(slicesDir).filter((f) => f.endsWith(".md")).sort();
|
|
24
|
+
for (const file of files) {
|
|
25
|
+
const doc = parseSliceDoc(readFileSync(join(slicesDir, file), "utf8"));
|
|
26
|
+
const key = file.slice(0, -".md".length);
|
|
27
|
+
for (const coveredKey of doc.covers) {
|
|
28
|
+
if (!coverage.has(coveredKey))
|
|
29
|
+
coverage.set(coveredKey, { doc, key });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return coverage;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/catalog/coverage.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,6FAA6F;AAC7F,6FAA6F;AAC7F,2FAA2F;AAC3F,gGAAgG;AAChG,4FAA4F;AAC5F,4FAA4F;AAC5F,gGAAgG;AAChG,0FAA0F;AAC1F,uDAAuD;AAEvD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAY,MAAM,eAAe,CAAC;AAWxD;;;;sCAIsC;AACtC,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAChD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;IAChD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC5C,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,aAAa,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACvE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACzC,KAAK,MAAM,UAAU,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACpC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC;gBAAE,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Slice } from "../model/model.js";
|
|
1
|
+
import { NormalizedModel, Slice } from "../model/model.js";
|
|
2
|
+
import { RefsResult } from "../model/refs.js";
|
|
2
3
|
import { Diagnostic } from "../model/validate.js";
|
|
3
4
|
import { DriftSignalKind } from "./driftSignal.js";
|
|
4
5
|
import { SliceDoc, SliceRef } from "./sliceDoc.js";
|
|
@@ -72,10 +73,27 @@ export interface SliceDocExport {
|
|
|
72
73
|
* em-tracker-bridge reads to find the mirrored ticket — its name/shape here is a cross-tool
|
|
73
74
|
* contract, not just an internal display field. */
|
|
74
75
|
tracking: string | null;
|
|
76
|
+
/** MIL-214: this slice's `version:` at the time a conform sweep last certified it (frontmatter
|
|
77
|
+
* `conformedVersion:`), written only by `em slice conform` — null when never certified. */
|
|
78
|
+
conformedVersion: number | null;
|
|
79
|
+
/** MIL-214: the target repo's revision that certification sweep diffed against (frontmatter
|
|
80
|
+
* `conformedAt:`), written only by `em slice conform` — null when never certified. */
|
|
81
|
+
conformedAt: string | null;
|
|
82
|
+
/** MIL-214: the local date that certification was recorded (frontmatter `conformedOn:`),
|
|
83
|
+
* written only by `em slice conform` — null when never certified. */
|
|
84
|
+
conformedOn: string | null;
|
|
75
85
|
}
|
|
76
86
|
export interface SliceDocJoinResult {
|
|
77
87
|
doc: SliceDocExport;
|
|
78
88
|
diagnostics: Diagnostic[];
|
|
89
|
+
/** MIL-208: non-null when this slice is a CONTINUATION of another slice — an again-view-only
|
|
90
|
+
* slice with no legacy doc of its own (see the module comment's "Legacy own doc wins")
|
|
91
|
+
* — naming that originating slice's export key. `doc` is byte-identical to the originating
|
|
92
|
+
* slice's own join in that case (the SAME object, not a re-derived copy): `em export
|
|
93
|
+
* --slice <again-key>` reports the real status via `doc` while `continuationOf` says why.
|
|
94
|
+
* Null for every ordinary slice, and for a continuation slice that still carries its own
|
|
95
|
+
* legacy doc (a `continuation-has-own-doc` warning fires instead — see rules.ts). */
|
|
96
|
+
continuationOf: string | null;
|
|
79
97
|
}
|
|
80
98
|
/**
|
|
81
99
|
* Resolve one slice's doc join. `baseDir` is the `.em` file's directory (doc paths, like note
|
|
@@ -84,4 +102,4 @@ export interface SliceDocJoinResult {
|
|
|
84
102
|
* entries use) so the returned diagnostics point at the same identities every other export
|
|
85
103
|
* diagnostic does — never a second identifier scheme.
|
|
86
104
|
*/
|
|
87
|
-
export declare function resolveSliceDocJoin(slice: Slice, sliceKey: string, baseDir: string, elementRefOf: (id: string) => string): SliceDocJoinResult;
|
|
105
|
+
export declare function resolveSliceDocJoin(model: NormalizedModel, refs: RefsResult, slice: Slice, sliceKey: string, baseDir: string, elementRefOf: (id: string) => string): SliceDocJoinResult;
|