@milehimikey/em 1.16.1 → 1.17.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.
Files changed (96) hide show
  1. package/.claude/skills/event-modeling/SKILL.md +1 -1
  2. package/.claude/skills/event-modeling-conform/SKILL.md +3 -2
  3. package/.claude/skills/event-modeling-conform/reference/conform.md +7 -0
  4. package/.claude/skills/event-modeling-design/SKILL.md +1 -1
  5. package/.claude/skills/event-modeling-discover/SKILL.md +1 -1
  6. package/.claude/skills/event-modeling-engagement/SKILL.md +22 -5
  7. package/.claude/skills/event-modeling-engagement/reference/engagement.md +5 -4
  8. package/.claude/skills/event-modeling-implement/SKILL.md +1 -1
  9. package/.claude/skills/event-modeling-implement/reference/implement.md +10 -8
  10. package/.claude/skills/event-modeling-review/SKILL.md +1 -1
  11. package/.claude/skills/event-modeling-shared/reference/em-dsl.md +17 -5
  12. package/.claude/skills/event-modeling-shared/reference/slice-doc-schema.md +26 -13
  13. package/.claude-plugin/marketplace.json +2 -2
  14. package/dist/catalog/docJoin.d.ts +13 -5
  15. package/dist/catalog/docJoin.js +6 -1
  16. package/dist/catalog/docJoin.js.map +1 -1
  17. package/dist/catalog/signedBodyValidate.d.ts +7 -0
  18. package/dist/catalog/signedBodyValidate.js +29 -0
  19. package/dist/catalog/signedBodyValidate.js.map +1 -0
  20. package/dist/catalog/sliceDoc.d.ts +53 -7
  21. package/dist/catalog/sliceDoc.js +89 -10
  22. package/dist/catalog/sliceDoc.js.map +1 -1
  23. package/dist/catalog/sliceReadyValidate.d.ts +15 -2
  24. package/dist/catalog/sliceReadyValidate.js +19 -19
  25. package/dist/catalog/sliceReadyValidate.js.map +1 -1
  26. package/dist/cli/defer.d.ts +32 -17
  27. package/dist/cli/defer.js +100 -82
  28. package/dist/cli/defer.js.map +1 -1
  29. package/dist/cli/engagement.d.ts +46 -0
  30. package/dist/cli/engagement.js +133 -1
  31. package/dist/cli/engagement.js.map +1 -1
  32. package/dist/cli/engagementFoundation.d.ts +47 -0
  33. package/dist/cli/engagementFoundation.js +164 -0
  34. package/dist/cli/engagementFoundation.js.map +1 -0
  35. package/dist/cli/frontmatterSurgery.d.ts +5 -0
  36. package/dist/cli/frontmatterSurgery.js +15 -0
  37. package/dist/cli/frontmatterSurgery.js.map +1 -1
  38. package/dist/cli/ledgerCheck.d.ts +5 -1
  39. package/dist/cli/ledgerCheck.js +50 -20
  40. package/dist/cli/ledgerCheck.js.map +1 -1
  41. package/dist/cli/ratify.d.ts +14 -2
  42. package/dist/cli/ratify.js +34 -6
  43. package/dist/cli/ratify.js.map +1 -1
  44. package/dist/cli/refsCheck.d.ts +78 -0
  45. package/dist/cli/refsCheck.js +153 -0
  46. package/dist/cli/refsCheck.js.map +1 -0
  47. package/dist/cli/revise.d.ts +10 -3
  48. package/dist/cli/revise.js +36 -8
  49. package/dist/cli/revise.js.map +1 -1
  50. package/dist/cli/sliceConform.js +9 -0
  51. package/dist/cli/sliceConform.js.map +1 -1
  52. package/dist/cli/status.d.ts +5 -4
  53. package/dist/cli/status.js +3 -3
  54. package/dist/cli/status.js.map +1 -1
  55. package/dist/cli/upgrade.d.ts +1 -1
  56. package/dist/cli/upgrade.js +113 -3
  57. package/dist/cli/upgrade.js.map +1 -1
  58. package/dist/cli.js +147 -31
  59. package/dist/cli.js.map +1 -1
  60. package/dist/emit/engagementJson.d.ts +4 -1
  61. package/dist/emit/engagementJson.js +25 -1
  62. package/dist/emit/engagementJson.js.map +1 -1
  63. package/dist/emit/json.d.ts +1 -1
  64. package/dist/emit/json.js +4 -1
  65. package/dist/emit/json.js.map +1 -1
  66. package/dist/emit/ledgerJson.d.ts +1 -1
  67. package/dist/emit/ledgerJson.js +6 -1
  68. package/dist/emit/ledgerJson.js.map +1 -1
  69. package/dist/emit/refsJson.d.ts +4 -0
  70. package/dist/emit/refsJson.js +19 -0
  71. package/dist/emit/refsJson.js.map +1 -0
  72. package/dist/emit/validateJson.d.ts +2 -2
  73. package/dist/emit/validateJson.js +7 -2
  74. package/dist/emit/validateJson.js.map +1 -1
  75. package/dist/mcp/server.js +37 -7
  76. package/dist/mcp/server.js.map +1 -1
  77. package/dist/model/rules.d.ts +18 -1
  78. package/dist/model/rules.js +20 -3
  79. package/dist/model/rules.js.map +1 -1
  80. package/dist/parser/lexer.d.ts +7 -1
  81. package/dist/parser/lexer.js +13 -2
  82. package/dist/parser/lexer.js.map +1 -1
  83. package/package.json +1 -1
  84. package/plugin/.claude-plugin/plugin.json +2 -2
  85. package/plugin/shared/reference/em-dsl.md +17 -5
  86. package/plugin/shared/reference/slice-doc-schema.md +26 -13
  87. package/plugin/skills/conform/SKILL.md +3 -2
  88. package/plugin/skills/conform/reference/conform.md +7 -0
  89. package/plugin/skills/design/SKILL.md +1 -1
  90. package/plugin/skills/discover/SKILL.md +1 -1
  91. package/plugin/skills/engagement/SKILL.md +22 -5
  92. package/plugin/skills/engagement/reference/engagement.md +5 -4
  93. package/plugin/skills/event-modeling/SKILL.md +1 -1
  94. package/plugin/skills/implement/SKILL.md +1 -1
  95. package/plugin/skills/implement/reference/implement.md +10 -8
  96. package/plugin/skills/review/SKILL.md +1 -1
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling
3
- em-version: 1.16.1
3
+ em-version: 1.17.0
4
4
  description: >-
5
5
  Use when the user runs `/event-modeling` (with or without a phase name), or wants to resume an
6
6
  event-modeling session without specifying which part of the process applies. Reads the model's
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling-conform
3
- em-version: 1.16.1
3
+ em-version: 1.17.0
4
4
  description: >-
5
5
  Use when checking a ratified event model (and its slice docs) for drift against the codebase
6
6
  that implements it — advisory only, never a gate, never an unprompted edit — or when walking
@@ -44,7 +44,8 @@ Ruling on a finding is a human gate, like ratifying a slice
44
44
  decides, and `em conform-supersede ... --locus <model|doc|code|none> --by <name>` records the
45
45
  ruling on the findings record (and stamps the report) — never rule on your own judgment. Once
46
46
  every finding touching a slice is ruled, `em slice conform <model-name>.em <key> --at <rev>`
47
- certifies that version of the slice.
47
+ certifies that version of the slice (`--at build:<id>` / `deploy:<id>` when the swept commit
48
+ will not stay reachable — a PR branch under squash/rebase merges; GH #261).
48
49
 
49
50
  End of phase: state file's `Last conformance:` marker updated (via `em state set-conformance` —
50
51
  refuses while any `implemented` slice still has an unruled finding; `--partial` escapes with a
@@ -319,8 +319,15 @@ slice with no unruled findings left:
319
319
 
320
320
  ```
321
321
  em slice conform <model-name>.em <slice-key> --at <target-repo revision>
322
+ em slice conform <model-name>.em <slice-key> --at <kind>:<id> # e.g. build:1234 — what the sweep exercised, when its commit will not stay reachable (GH #261)
322
323
  ```
323
324
 
325
+ If you certified from a pull-request branch and the repo squash- or rebase-merges, the branch
326
+ HEAD will dangle once the branch is deleted. Either pass a commit the target branch will keep
327
+ (the merge commit) or record the deployment/build you actually swept as `--at build:<id>` /
328
+ `--at deploy:<id>` / `--at env:<id>` — and write the same string as the findings file's
329
+ `revision`, so the findings-check gate still matches.
330
+
324
331
  — records `conformedVersion`/`conformedAt`/`conformedOn` on that slice's doc, so
325
332
  `driftSignal` reads `in-sync` again (it reads `uncertified` for an implemented slice that's never
326
333
  been through this) instead of just trusting `implementedIn`. Legal only for `status: implemented`
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling-design
3
- em-version: 1.16.1
3
+ em-version: 1.17.0
4
4
  description: >-
5
5
  Use when structuring a draft event model into swimlanes and the four patterns (State Change,
6
6
  State View, Automation, Translation), evaluating a model's structural completeness, or writing
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling-discover
3
- em-version: 1.16.1
3
+ em-version: 1.17.0
4
4
  description: >-
5
5
  Use when starting a brand-new event model from scratch — greenfield discovery: brainstorming
6
6
  past-tense events, storyboarding the happy path, finding the commands and read models — or when
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling-engagement
3
- em-version: 1.16.1
3
+ em-version: 1.17.0
4
4
  description: >-
5
5
  Use when leading an engagement: building a named set of ratified event-modeling slices
6
6
  (`em engagement`) into one independent PR per slice, each against main, by dispatching the
@@ -47,9 +47,17 @@ Run the shared preconditions first (tool check, bundle currency, locate the mode
47
47
  beside the model, or `.specify/memory/constitution.md`). STOP if it is missing or its
48
48
  `ratifiedBy:` is empty (spec-kit: no `**Ratified**:` footer). Say so and point at
49
49
  `event-modeling-implement`'s §7; never draft house rules to get moving.
50
- 2. **Foundation PR merged.** Ask the human for the foundation PR (implement.md §8) and confirm it
51
- has merged into `main` (`gh pr view <n> --json state` shows `MERGED`). STOP if there is none
52
- or it is still open. No slice branch is cut before it lands.
50
+ 2. **Foundation is in the code.** Do not ask the human whether the foundation PR (implement.md
51
+ §8) landed — check: `em engagement foundation <model>.em <slug> --code <repo root>` (GH #240;
52
+ `--json` when you need the fields). It reports every event the engagement's slices emit or
53
+ consume as `present`, `incomplete` (which fields, which tag fields are missing — named), or
54
+ `missing-event`. Any `missing-event`: STOP — the foundation has not landed for that event; ask
55
+ for the foundation PR and confirm it merged into `main` (`gh pr view <n> --json state` shows
56
+ `MERGED`), then re-run. Any `incomplete`: **one question to the human**, listing every gap the
57
+ report names (an implementer never discovers these alone) — the fix is a foundation follow-up
58
+ on `main`, never a slice PR. All `present`: go on. No slice branch is cut before this is clean.
59
+ The check is a text scan of the target tree, not a compiler: a `present` event may still fail
60
+ to type-check in the slice PR, and that is the slice PR's job to surface.
53
61
  3. **Agent models.** Read the line `- **Agent models:** implementer=<model>,
54
62
  validator=<model>, reviewer=<model>, critic=<model|codex>`. If it is absent, say once:
55
63
  "no Agent models line — using implementer=sonnet, validator=sonnet, reviewer=sonnet,
@@ -72,12 +80,21 @@ Run the shared preconditions first (tool check, bundle currency, locate the mode
72
80
  Run `em engagement plan <model>.em <slug>` (`--json` when you need the fields). Present it in
73
81
  plain terms: each level, its width against the ceiling (`parallel`), each slice's branch (every
74
82
  base is `main`), and every held slice with its reason (`not-ready`,
75
- `upstream-outside-engagement-unmerged`, or `human`). Then ask exactly one question:
83
+ `upstream-outside-engagement-unmerged`, or `human`). Then the plan's **`pre-flight:` block** (GH
84
+ #239): the model-wide gaps the engagement's slices share — a `repeated-invariant` with no single
85
+ enforcing slice, an `event-without-tag` whose consistency boundary is undeclared, a
86
+ `shared-trigger` (one `ui`, two slices, no endpoint owner), a `doc-model-mismatch`. These are
87
+ exactly what every implementer would otherwise stop on and report separately. Put them to the
88
+ human **in the same single question round** as the ceiling, one bullet each with the slices it
89
+ spans, and ask for a ruling on each (the answer goes where it belongs: the model, the foundation
90
+ PR, a slice doc, or `.event-modeling.md` for a deferral). Then ask exactly one question:
76
91
 
77
92
  > "Ceiling N from the plan; proceed?"
78
93
 
79
94
  Ask it once per engagement. If the human names a lower number, use it for this session. **Never
80
95
  ask "which slice first"**: the levels decide the order, and the ceiling decides how many at once.
96
+ A pre-flight finding never holds a slice: if the human says "proceed anyway" on one, dispatch
97
+ and make sure each implementer's brief carries the ruling, so no agent rediscovers it.
81
98
  A held slice is never started; the plan releases it when its hold clears.
82
99
 
83
100
  ## 3. Per level: cut the worktree, then dispatch the implementer
@@ -74,11 +74,12 @@ constitution. The implementer stops and reports it as the doc line plus the ques
74
74
  4. Carry on with every other startable slice. Never answer the question yourself, never edit the
75
75
  doc, and never let the implementer guess.
76
76
 
77
- A question the build can finish without (it does not block the slice) is not a gap: queue it with
77
+ A question the build can finish without (it does not block the slice) is not a gap: defer it with
78
78
  `em slice defer <model>.em <key> "<question>" --until v<n> --decision "<what this version does>"`
79
- (GH #236). On a ratified doc that never edits the body — `ratifiedHash` and `--slice-ready` stay
80
- green — and records the question in `.event-modeling.md` for `<key>@v<N+1>`; `mark-implemented`
81
- at merge opens v<N+1> as a draft with it in Open Questions. Never write the `- [ ]` into the
79
+ (GH #253). On a ratified doc that appends the already-deferred `- [x]` item to the doc's Open
80
+ Questions, outside `ratifiedHash` — the hash and `--slice-ready` stay green, and the question is
81
+ visible in the ratified doc; `mark-implemented` at merge opens v<n> as a draft with it reopened
82
+ as `- [ ]`. Never write a `- [ ]` into the
82
83
  ratified doc, and do not run `em slice revise` for it (an unshipped ratified doc refuses
83
84
  `revise` without `--withdraw`).
84
85
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling-implement
3
- em-version: 1.16.1
3
+ em-version: 1.17.0
4
4
  description: >-
5
5
  Use when building a single ratified event-modeling slice (status: ready-to-implement) into
6
6
  merged, tested code — the one phase where the agent builds rather than facilitates. Gates on
@@ -159,12 +159,14 @@ undocumented ordering, a contradiction with adjacent code. The discipline:
159
159
  your recommendation. The human resolves it — at the model, where the resolution lands as an
160
160
  answered open question or a small ratified delta alongside your fix, so the decision is
161
161
  recorded instead of buried in an implementation diff.
162
- - **A question this build will not wait on is queued, never written into the doc** (GH #236). On a
163
- ratified doc the body is the signed spec: `em slice defer <model>.em <slice-key> "<question>"
164
- --until v<n> --decision "<what this version does>"` records it in `.event-modeling.md` as queued
165
- for `<key>@v<N+1>` and leaves the doc — and `ratifiedHash`, and `--slice-ready` — untouched. When
166
- the slice merges (`mark-implemented`) or is revised, the queued question is injected into the
167
- v<N+1> draft's Open Questions. Never add the `- [ ]` item to the ratified doc yourself.
162
+ - **A question this build will not wait on is deferred through `em slice defer`, never written
163
+ into the doc by hand** (GH #253). On a ratified doc the body is the signed spec, but a deferral
164
+ sits outside `ratifiedHash`: `em slice defer <model>.em <slice-key> "<question>" --until v<n>
165
+ --decision "<what this version does>"` appends the already-deferred `- [x]` item to the doc's
166
+ Open Questions — visible to the next reader — and `ratifiedHash` and `--slice-ready` stay
167
+ untouched. When the slice merges (`mark-implemented`) or is revised, the item is reopened as
168
+ `- [ ]` in the v<n> draft. Never add a `- [ ]` item to the ratified doc yourself: that does
169
+ move the hash.
168
170
  - **How a delta is ratified on a doc that never shipped** (it is `ready-to-implement` with
169
171
  `ratifiedBy` set) when the spec itself must change: once the human has answered, the doc changes
170
172
  by `em slice revise <model>.em <slice-key> --withdraw` (MIL-283: opens the next version as a
@@ -248,8 +250,8 @@ Prefer it over hand-editing the doc's frontmatter. It also writes the **shipped
248
250
  (`shippedVersion:`/`shippedRef:`/`shippedOn:`, MIL-284) — what every reader decides "has this
249
251
  shipped?" on since 1.15.0 — and, when the ratified doc deferred a question to the next version,
250
252
  **opens that version as a `draft` on the same write** (MIL-283: `status: draft`, `version` bumped,
251
- the question back to `- [ ]`; the version you built stays shipped) — questions queued with `em slice
252
- defer` while the doc was ratified (GH #236) are injected into that draft too. If it prints `opened draft
253
+ the question back to `- [ ]`; the version you built stays shipped) — a question deferred with `em
254
+ slice defer` while the doc was ratified (GH #253) is one of those. If it prints `opened draft
253
255
  v<N+1>`, say so in your report: the slice has known work, and a design session, not you, decides it.
254
256
 
255
257
  Then, if the project keeps a model README (from `../../event-modeling-shared/templates/model-readme.md`), run
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling-review
3
- em-version: 1.16.1
3
+ em-version: 1.17.0
4
4
  description: >-
5
5
  Use when starting em's live browser viewer (`em watch --serve`) so a team can watch a model
6
6
  update in real time, or facilitating a SCHEDULED stakeholder walkthrough that steps through
@@ -71,26 +71,28 @@ em slice mark-implemented <file> <slice-key> <pr-url> --on <date> # merge date
71
71
  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
72
72
  em slice review <file> <slice-key> --by <name> # the reviewer's (or facilitator's) name
73
73
  em slice review <file> <slice-key> --on <date> # review date, YYYY-MM-DD (default: today, local date)
74
- 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. The review gate is a check on the doc's current `status:`, not on whether `reviewedBy:`/`reviewedOn:` are populated: a doc at `reviewed` passes; a `ready-to-implement` doc only when the same signer is completing their own record (since 1.15.0, MIL-283 — a new sign-off is a new version: `em slice revise`); any other status — a `draft` that never went through `em slice review` — is refused unless --skip-review is passed. Idempotent on the same --by/--on pair; refuses to overwrite a different one already recorded, and (MIL-284) a same-pair re-run on a doc whose body moved after sign-off; never touches `version:` or the doc body
74
+ 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. The review gate is a check on the doc's current `status:`, not on whether `reviewedBy:`/`reviewedOn:` are populated: a doc at `reviewed` passes; a `ready-to-implement` doc only when the same signer is completing their own record (since 1.15.0, MIL-283 — a new sign-off is a new version: `em slice revise`); any other status — a `draft` that never went through `em slice review` — is refused unless --skip-review is passed. Idempotent on the same --by/--on pair; refuses to overwrite a different one already recorded, and (MIL-284) a same-pair re-run on a doc whose body moved after sign-off; never touches `version:` or the doc body. Inside a git work tree also records `ratifiedRef:` (HEAD, refusing a doc with uncommitted changes) and always `ratifiedHash:`; with --no-ref (GH #255) only the hash — for a repo whose squash/rebase merges would leave the ref unreachable — and git is not consulted
75
75
  em slice ratify <file> <slice-key> --by <name> # the ratifier's name
76
+ em slice ratify <file> <slice-key> --no-ref # record ratifiedHash: only, no ratifiedRef: (GH #255) — the signed content keeps its identity, nothing points at a commit a squash or rebase merge would orphan; the uncommitted-changes check does not apply
76
77
  em slice ratify <file> <slice-key> --on <date> # ratification date, YYYY-MM-DD (default: today, local date)
77
- em slice ratify <file> <slice-key> --skip-review # ratify without a recorded review — prints a loud notice on stderr
78
+ em slice ratify <file> <slice-key> --skip-review # ratify without a recorded review — prints a loud notice on stderr and records `reviewSkipped: <status>` on the doc (GH #260) so the bypass is visible to later readers, `em export` and `--slice-ready --json`; cleared by `em slice revise`
78
79
  em slice ratify <file> <slice-key> --meaning-unchanged # API-first sign-off (MIL-238): this version does not change what the public contract means — records `meaningConfirmed: true`; required (or --contract-change) on a slice touching a `public` element
79
80
  em slice ratify <file> <slice-key> --contract-change <why> # API-first sign-off (MIL-238): a consumer must read this change differently, and why — records `contractChange: "<why>"`
80
- em slice revise <file> <slice-key> # open the next version of a slice doc as a `draft` (MIL-283): bumps `version:`, flips `status:` to `draft`, clears the prior version's review and sign-off (`reviewedBy/On`, `ratifiedBy/On/Ref/Hash`, `meaningConfirmed`/`contractChange`) and re-opens the questions deferred to the new version. The shipped version stays shipped: `implementedIn:` and the `shipped*` keys are untouched (written first on a doc shipped before 1.15). Applies to `status: implemented` (the shipped case) and to a ratified `ready-to-implement` doc (ratification withdrawn, never shipped); a `ready-to-implement` doc with no `ratifiedBy:` reopens as draft at the same version; `draft`/`reviewed` refuse — the next version is already open. The new version then takes the normal road: `em slice review --by`, `em slice ratify --by`. Questions queued by `em slice defer` for the new version (GH #236) are injected into its Open Questions. A ratified, never-shipped doc REFUSES without --withdraw (revising withdraws the only implementable version; queue a question with `em slice defer` instead)
81
+ em slice revise <file> <slice-key> # open the next version of a slice doc as a `draft` (MIL-283): bumps `version:`, flips `status:` to `draft`, clears the prior version's review and sign-off (`reviewedBy/On`, `ratifiedBy/On/Ref/Hash`, `meaningConfirmed`/`contractChange`) and re-opens the questions deferred to the new version. The shipped version stays shipped: `implementedIn:` and the `shipped*` keys are untouched (written first on a doc shipped before 1.15). Applies to `status: implemented` (the shipped case) and to a ratified `ready-to-implement` doc (ratification withdrawn, never shipped); a `ready-to-implement` doc with no `ratifiedBy:` reopens as draft at the same version; `draft`/`reviewed` refuse — the next version is already open. The new version then takes the normal road: `em slice review --by`, `em slice ratify --by`. A ratified, never-shipped doc REFUSES without --withdraw (revising withdraws the only implementable version; record a question with `em slice defer` instead — it sits outside the hash, GH #253). With --keep-version (GH #262) a ratified, never-shipped doc reopens as a draft at the SAME `version:` — same status flip and sign-off clearing, no bump — for a project that holds every slice at its initial version until a first release; refused on a shipped doc
81
82
  em slice revise <file> <slice-key> --withdraw # GH #236: required on a ratified, never-shipped doc — confirms withdrawing the ratification of the only implementable version
83
+ em slice revise <file> <slice-key> --keep-version # GH #262: reopen a ratified, never-shipped doc as a draft at the same `version:` (no bump) — a correction before a first release, not a delta; refused on a shipped doc, whose version must stay distinct from the next one
82
84
  em slice reratify <file> <slice-key> # DEPRECATED alias of `em slice revise` (MIL-283, since 1.15.0; removed in a later minor). Until 1.14 this left the doc at an unsigned `ready-to-implement`; it now opens a `draft` of the next version like `revise`. The --meaning-unchanged/--contract-change flags are accepted and ignored with a notice — the API-first confirmation is taken by `em slice ratify` on the new version
83
85
  em slice reratify <file> <slice-key> --meaning-unchanged # ignored since 1.15.0 (see above)
84
86
  em slice reratify <file> <slice-key> --contract-change <why> # ignored since 1.15.0 (see above)
85
87
  em slice reratify <file> <slice-key> --withdraw # see `em slice revise --withdraw`
86
- em slice defer <file> <slice-key> [question] # record a question this version will not answer as deferred to a later version (MIL-275): rewrites the single unchecked `## Open Questions` item containing <question> as `- [x] <item> — v<current>: <decision>; deferred to v<n> (<date>[, <by>])` so `--slice-ready` passes without a guess, and mirrors it into `.event-modeling.md` (the parking lot and a dated Decisions-log bullet; the file must exist, it is never created). Idempotent; `em slice reratify` re-opens the item when it bumps to v<n>. With --from-issue <text> instead of <question> (MIL-281): promotes the single open `issue "..."` on the slice's own elements containing <text> into the doc's Open Questions as that same deferred item, mirrors it, and removes the `issue` clause from the .em — the one-command path for a question raised in a review session. On a RATIFIED (`ready-to-implement` + `ratifiedBy:`) or shipped (`implemented`) doc (GH #236) the doc is NOT edited — its body is the signed spec — and the question is queued in `.event-modeling.md` for v<N+1>; `em slice revise` / `mark-implemented` inject it into the next draft
88
+ em slice defer <file> <slice-key> [question] # record a question this version will not answer as deferred to a later version (MIL-275): rewrites the single unchecked `## Open Questions` item containing <question> as `- [x] <item> — v<current>: <decision>; deferred to v<n> (<date>[, <by>])` so `--slice-ready` passes without a guess, and mirrors it into `.event-modeling.md` (the parking lot and a dated Decisions-log bullet; the file must exist, it is never created). Idempotent; `em slice reratify` re-opens the item when it bumps to v<n>. With --from-issue <text> instead of <question> (MIL-281): promotes the single open `issue "..."` on the slice's own elements containing <text> into the doc's Open Questions as that same deferred item, mirrors it, and removes the `issue` clause from the .em — the one-command path for a question raised in a review session. On a RATIFIED (`ready-to-implement` + `ratifiedBy:`) or shipped (`implemented`) doc (GH #253) the already-deferred `[x]` item is APPENDED to the doc's Open Questions — `ratifiedHash` excludes the section heading and its `deferred to v<n>` items, so the signature, `--slice-ready` and ratify's re-run stay valid, and the question is visible in the ratified doc; a pre-1.17 whole-body hash is re-stamped in the same edit. Refuses a doc whose body already fails its hash
87
89
  em slice defer <file> <slice-key> [question] --until <version> # the version that must answer it, v<n> (greater than the doc's version)
88
90
  em slice defer <file> <slice-key> [question] --decision <text> # what this version does instead
89
91
  em slice defer <file> <slice-key> [question] --from-issue <text> # defer a captured `issue "..."` on this slice instead of a doc Open Question (case-sensitive substring of its text)
90
92
  em slice defer <file> <slice-key> [question] --by <name> # who deferred it
91
93
  em slice defer <file> <slice-key> [question] --on <date> # deferral date, YYYY-MM-DD (default: today, local date)
92
94
  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 a shipped slice (`status: implemented`, or any status with a `shippedVersion:` — MIL-283) with an `implementedIn:` link; `conformedVersion:` is the shipped version. 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.
93
- em slice conform <file> <slice-key> --at <rev> # the target-repo revision this certification sweep diffed against
95
+ em slice conform <file> <slice-key> --at <rev> # the target-repo revision this certification sweep diffed against — or, when what was exercised is not a commit that stays reachable (a per-PR environment under squash/rebase merges, a build or image), an opaque `<kind>:<id>` such as build:1234 or deploy:eu-1-2026-10-15 (GH #261); recorded verbatim, skipped by git-reachability checks
94
96
  em slice conform <file> <slice-key> --on <date> # certification date, YYYY-MM-DD (default: today, local date)
95
97
  em slice conform <file> <slice-key> --skip-findings-check # certify even with unruled findings in scope — prints a loud notice on stderr
96
98
  em changelog <file> # render a model's git history as a business-readable ledger (see docs/cli.md)
@@ -138,9 +140,16 @@ em validate <file> --list-divergences # print only
138
140
  em validate <file> --list-public # print only commands, events and views marked `public` (slice, kind, name, line) — an integration-surface audit, never fails the build
139
141
  em validate <file> --fail-on-issues # exit non-zero if the model has any open `issue`s (opt-in — issues are warnings and don't block by default)
140
142
  em validate <file> --slice-ready <key> # readiness gate for one slice (export key): status ready-to-implement, doc resolvable via note binding, zero unchecked Open Questions, a recorded ratifiedBy, and — for a slice touching a `public` element — a current contracts/<model key>.tsp; exits non-zero if not ready (MIL-87, MIL-259, MIL-238)
143
+ em validate <file> --require-ratified-hash # with --slice-ready (GH #256): strict mode — a ready-to-implement doc with no `ratifiedHash:` is NOT ready (`slice-ready-missing-ratified-hash`, error; `ready: false` in --json). Off by default so docs ratified before em 1.15 keep passing; turn it on once legacy docs are re-ratified
144
+ em validate <file> --check-signed-bodies # opt-in (GH #257): compare every slice doc that records a `ratifiedHash:` — ready, implemented, any status — to its body; a mismatch is `slice-body-changed-since-ratification` (error). A pre-1.17 whole-body hash with an intact body passes; a deferral written by `em slice defer` is outside the hash. The one check that still watches a shipped doc's signed content
141
145
  em validate <file> --json # print a JSON document instead of text — works on a model WITH errors, unlike `em export` (MIL-128, see docs/cli.md); exit codes are unchanged
142
146
  em migrate <file> # rewrite the old two-slice Automation/Translation shape into the merged single-slice shape MIL-120 made canonical (see docs/cli.md)
143
147
  em migrate <file> --write # apply the rewrite to the file (default: dry run — report only, write nothing)
148
+ em refs <file> # check that every commit a slice doc records — `ratifiedRef:`, `shippedRef:`, a bare `conformedAt:` — still resolves and is reachable from a branch (GH #258): per doc, per field, `ancestor` / `not-ancestor` / `unresolved` / `undecidable` (a shallow clone never passes). Squash and rebase merges orphan the PR-branch HEAD ratify recorded; nothing else in em resolves a ref. Opt-in CI check, like `em ledger` — never part of `em validate`. Local object store only, no network. Kinded `conformedAt` values (build:…) are skipped; docs with no ref fields are not reported
149
+ em refs <file> --reachable-from <rev> # the branch or commit every ref must be an ancestor of (e.g. origin/main)
150
+ em refs <file> --waive <slice-key> # excuse this slice's non-ancestor/unresolved/undecidable results from the exit code (repeatable); still reported
151
+ em refs <file> --waive-file <path> # a baseline file of slice keys to waive, one per line (`#` comments allowed); missing file = no waivers
152
+ em refs <file> --json # print a JSON document instead of the text report (see docs/cli.md)
144
153
  em ledger <file> # check slice docs' version: field agrees with their content across two git revisions (opt-in CI check, MIL-89 — never part of `em validate`, see docs/ci.md)
145
154
  em ledger <file> --from <rev> # baseline revision
146
155
  em ledger <file> --to <rev> # compare revision (default: current working tree)
@@ -209,6 +218,9 @@ em engagement new <file> <slug> --tracking <key> # an issue-t
209
218
  em engagement new <file> <slug> --force # overwrite an existing engagement file with this slug
210
219
  em engagement plan <file> <slug> # the engagement's build plan: dependency levels over model.edges (loops-to excluded), and per slice its readiness, branch impl/<key>, base (always main — MIL-280), and any hold
211
220
  em engagement plan <file> <slug> --json # print a JSON document instead of text (same document as the MCP engagement_plan tool)
221
+ em engagement foundation <file> <slug> # GH #240: is the foundation PR (implement.md §8) actually in the code for the events this engagement's slices emit and consume? A text scan of --code: an event is present when a file carries an identifier derived from its name (OrderPlaced / order_placed / ORDER_PLACED / order-placed), its model fields and tag fields are then looked for in those files. Per event: present | incomplete (missing-field / missing-tag, named) | missing-event — so "foundation absent" and "foundation incomplete" are different reports. Exits 1 unless every event is present. Proves the contract was written down, not that it type-checks
222
+ em engagement foundation <file> <slug> --code <dir> # the target repository (or the directory the constitution's "where a slice's code lives" rule points at)
223
+ em engagement foundation <file> <slug> --json # print a JSON document instead of text (same document as the MCP engagement_foundation tool)
212
224
  em engagement set <file> <slug> <key> # the only write path to the Ledger: set one slice's state (and optionally branch/base/pr); idempotent; merged is terminal; --state held records a human hold
213
225
  em engagement set <file> <slug> <key> --state <state> # one of: planned | building | validating | review | awaiting-merge | merged | held | gap
214
226
  em engagement set <file> <slug> <key> --branch <name> # the slice's branch
@@ -67,17 +67,18 @@ to decide `frontmatter-invalid` without re-deriving frontmatter-shape rules of i
67
67
  | `reviewedOn` | string | `YYYY-MM-DD` | written only by `em slice review` (MIL-201); joined into `em export`'s `slice.doc.reviewedOn` (schema `1.11`) |
68
68
  | `ratifiedBy` | string | free text (typically a person's name) | written only by `em slice ratify` (MIL-165 — see [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-slice-ratify-file-slice-key---by-name)); joined into `em export`'s `slice.doc.ratifiedBy` (schema `1.8`) and `em slice index`'s Ratified by column |
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
- | `ratifiedRef` | string | full commit sha | written only by `em slice ratify` (MIL-284 — see [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-slice-ratify-file-slice-key---by-name)) when the model directory is inside a git repository: `HEAD` at ratification, the commit whose tree holds the body that was signed (ratify refuses a doc with uncommitted changes so this holds). Absent when ratified before 1.15 or outside git. Cleared by `em slice reratify`. Joined into `em export`'s `slice.doc.ratifiedRef` (schema `1.16`). Not a target-repo revision: `em slice conform --at` still names that itself |
71
- | `ratifiedHash` | string | `sha256:<64 hex>` | written only by `em slice ratify` (MIL-284): `sha256` over the doc body (everything after the frontmatter fence, EOLs normalised) — the signed content's identity without git. Cleared by `em slice reratify`. Read by `em validate --slice-ready` (`slice-ready-body-changed-since-ratification`); joined into `em export`'s `slice.doc.ratifiedHash` (schema `1.16`) |
70
+ | `ratifiedRef` | string | full commit sha | written only by `em slice ratify` (MIL-284 — see [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-slice-ratify-file-slice-key---by-name)) when the model directory is inside a git repository: `HEAD` at ratification, the commit whose tree holds the body that was signed (ratify refuses a doc with uncommitted changes so this holds). Absent when ratified before 1.15, outside git, or with `em slice ratify --no-ref` (GH #255 — for a repo whose squash/rebase merges would leave the commit unreachable from the target branch; `--no-ref` also removes a line already present). **An address, not the identity:** valid only while the commit stays reachable; `ratifiedHash` is what identifies the signed content. Cleared by `em slice revise`. Joined into `em export`'s `slice.doc.ratifiedRef` (schema `1.16`). Not a target-repo revision: `em slice conform --at` still names that itself |
71
+ | `ratifiedHash` | string | `sha256:<64 hex>` | written only by `em slice ratify` (MIL-284): `sha256` over the doc body (everything after the frontmatter fence, EOLs normalised) **minus what describes a later version** (GH #253, since 1.17.0): inside `## Open Questions` the heading line, blank lines and every `deferred to v<n>` item are left out, then trailing whitespace is trimmed — so `em slice defer` can record a question on a ratified or shipped doc without moving the hash, while answered `- [x]` history, any `- [ ]`, and every other section stay signed. The signed content's identity without git. A hash recorded before 1.17.0 (whole body) is still read as intact; `em upgrade`'s `ratified-hash-scope` step re-stamps it. Cleared by `em slice revise`. Read by `em validate --slice-ready` (`slice-ready-body-changed-since-ratification`) and by `ratify`'s same-sign-off re-run; joined into `em export`'s `slice.doc.ratifiedHash` (schema `1.16`) |
72
72
  | `shippedVersion` | integer | positive integer | written only by `em slice mark-implemented` (MIL-284): the doc's `version:` when the merge was recorded. With `shippedRef`/`shippedOn`/`implementedIn`, joined into `em export`'s `slice.doc.shipped` (schema `1.16`). Additive in 1.15 — `status`/`implementedIn` still carry the lifecycle for every reader |
73
- | `shippedRef` | string | full commit sha | written only by `em slice mark-implemented` (MIL-284): the doc's `ratifiedRef` at merge time, i.e. the ref the shipped version was signed at; absent when the doc had none |
73
+ | `shippedRef` | string | full commit sha | written only by `em slice mark-implemented` (MIL-284): the doc's `ratifiedRef` at merge time, i.e. the ref the shipped version was signed at; absent when the doc had none (ratified before 1.15, outside git, or with `--no-ref`, GH #255). Same caveat as `ratifiedRef`: an address, valid while reachable — `ratifiedHash` identifies the content |
74
74
  | `shippedOn` | string | `YYYY-MM-DD` | written only by `em slice mark-implemented` (MIL-284): the local date of the merge record, or `--on <date>` |
75
75
  | `meaningConfirmed` | boolean | `true` | written only by `em slice ratify --meaning-unchanged` (MIL-238 — see [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-slice-ratify-file-slice-key---by-name)): the API-first sign-off on a public-touching slice — this version does not change what the public contract means. Joined into `em export`'s `slice.doc.meaningConfirmed` (schema `1.15`; `false` when absent) |
76
76
  | `contractChange` | string | quoted free text (`contractChange: "<why>"`) | written only by `em slice ratify --contract-change "<why>"` (MIL-238): the API-first sign-off on a public-touching slice — why a consumer must read this change differently. Joined into `em export`'s `slice.doc.contractChange` (schema `1.15`, quotes stripped; `null` when absent) |
77
+ | `reviewSkipped` | string | a `status` value (`draft`, …) | written only by `em slice ratify --skip-review` (GH #260 — see [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-slice-ratify-file-slice-key---by-name)), and only when the bypass is what let the ratification through: the status the doc was ratified from. A ratification that passed the review gate writes nothing. Cleared by `em slice revise` with the rest of the sign-off. Joined into `em export`'s `slice.doc.reviewSkipped` (schema `1.18`, `null` when absent) and `em validate --slice-ready --json`'s top-level `reviewSkipped` (schema `1.3`) |
77
78
  | `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[]` |
78
79
  | `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 |
79
80
  | `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 |
80
- | `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 |
81
+ | `conformedAt` | string | a target-repo revision, or `<kind>:<id>` (NOT a `<slice-key>@v<N>` lineage ref) | written only by `em slice conform` (MIL-214): the revision that certification sweep diffed against — or, since 1.17.0 (GH #261), an opaque identifier with an explicit kind (`build:1234`, `deploy:eu-1-2026-10-15`) for what was exercised when that is not a commit that stays reachable (a PR-branch HEAD under squash/rebase merges). A bare value is git (`parseConformedAt()`); reachability checks skip a kinded value. Joined into `em export`'s `slice.doc.conformedAt` (schema `1.13`) and `em slice index`'s Conformed column |
81
82
  | `conformedOn` | string | `YYYY-MM-DD` | written only by `em slice conform` (MIL-214). Joined into `em export`'s `slice.doc.conformedOn` (schema `1.13`) |
82
83
 
83
84
  Five keys — `schemaVersion`/`pattern`/`swimlane`/`status`/`version` — are what
@@ -98,6 +99,7 @@ convention, not parser-enforced.
98
99
  | `covers` | optional in every state — present only on a doc that deliberately also serves another slice (MIL-121, see below); most docs never carry it |
99
100
  | `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) |
100
101
  | `ratifiedBy`, `ratifiedOn` | optional in every state, but `ready-to-implement` needs `ratifiedBy` to pass `em validate --slice-ready` (`slice-ready-not-ratified`, MIL-259) — present once `em slice ratify` (MIL-165) has run; `em slice reratify` clears both. `em upgrade` (`ratified-signoff`, 1.14) grandfathers a `version: 1` `ready-to-implement` doc that never had one by writing `ratifiedBy: "grandfathered (unsigned before em 1.14)"` and `ratifiedOn:` the upgrade date |
102
+ | `reviewSkipped` | optional in every state — present only when `em slice ratify --skip-review` is what let the ratification through (GH #260); the value is the status it skipped from. Written right after `ratifiedOn:`; cleared by `em slice revise` with the rest of the sign-off. Absent on every ratification that passed the review gate, and on docs ratified with `--skip-review` before 1.17.0 |
101
103
  | `meaningConfirmed`, `contractChange` | optional in every state, at most one present — written right after `ratifiedOn:` by `em slice ratify` and right after `version:` by `em slice reratify` (MIL-238). On a **public-touching** slice (one owning a `public` command, event or view) both commands refuse without `--meaning-unchanged` or `--contract-change "<why>"`, so a doc ratified on 1.14+ carries one; elsewhere either is optional. `em slice reratify` clears both before writing its own (they describe the prior version, same as `reviewedBy`/`ratifiedBy`). `em status` counts public-touching `ready-to-implement`/`implemented` docs with neither (`publicSlicesUnconfirmed`) |
102
104
  | `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) |
103
105
  | `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) |
@@ -490,7 +492,11 @@ not deleted: `em slice defer` checks it and rewrites it as `- [x] <original> —
490
492
  `em slice revise` (and `mark-implemented`, which opens v<n> at merge when something is deferred to it) reads: when the doc reaches v<n> it rewrites each such item back to
491
493
  `- [ ] <original>`, so the question must be resolved or re-deferred before `--slice-ready` passes
492
494
  again. The prune rule above does not apply to a deferred item before v<n> (it stays as the
493
- record); once reopened it is an ordinary open question.
495
+ record); once reopened it is an ordinary open question. A deferred item describes v<n>, not the
496
+ version that was signed, so it sits **outside `ratifiedHash`** (GH #253, with the section heading
497
+ and its blank lines; see the `ratifiedHash` row above) — which is what lets `em slice defer` write
498
+ one into a ratified or shipped doc. Every other line of the section — an answered `- [x]`, a hand-added
499
+ `- [ ]` — is inside the hash and moves it.
494
500
 
495
501
  **Not a parsing/grammar change.** `countOpenQuestions()` (`sliceDoc.ts`) and
496
502
  `slice-ready-open-questions-unchecked` (`sliceReadyValidate.ts`,
@@ -521,6 +527,10 @@ alone — v<N> stays shipped. `em slice mark-implemented` does the same automati
521
527
  question was deferred to v<N+1> (`em slice defer`), so known work is on the list the moment the
522
528
  previous version lands. Version 2 then takes both human gates like version 1 did: `em slice review
523
529
  --by`, then `em slice ratify --by` (which records a fresh `ratifiedRef`/`ratifiedHash`).
530
+ A ratified doc that never shipped may instead be reopened at the **same** `version:` with
531
+ `em slice revise --withdraw --keep-version` (GH #262) — a correction before a first release, not a
532
+ delta, so no `## Delta` is owed; the status flip and sign-off clearing are the same. Refused on a
533
+ shipped doc: the shipped version keeps its number.
524
534
 
525
535
  The deliberate mismatch — `version: 2` open while `implementedIn`/`shippedVersion` still name v1's
526
536
  work — is not staleness, it's the **drift signal**: `em export`'s `slice.doc.driftSignal` is
@@ -545,14 +555,17 @@ ratification of v<N> is withdrawn and nothing shipped, so no shipped record is w
545
555
  withdraws the only implementable version, `em slice revise` **refuses it without `--withdraw`**
546
556
  (GH #236).
547
557
 
548
- **Questions found against a ratified or shipped version are queued, not written into the body**
549
- (GH #236). `ratifiedHash` covers the whole body, `## Open Questions` included, so `em slice defer` on
550
- a `ready-to-implement` + `ratifiedBy:` or `implemented` doc does not edit the doc: it records the
551
- question in the model's `.event-modeling.md` as queued for `<key>@v<N+1>` (exact bullet shape in
552
- [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-slice-defer-file-slice-key-question)), keeping `ratifiedHash` and `--slice-ready`
553
- valid. When v<N+1> opens as a draft — `mark-implemented` at merge, or `revise` — each queued item is
554
- injected into that draft's `## Open Questions` (unchecked, carrying its decision) and the queue is
555
- cleared. `em export` reports the waiting count as `slice.doc.queuedForNext` (schema `1.17`). **A
558
+ **Questions found against a ratified or shipped version are written into the body, outside the
559
+ hash** (GH #253, superseding GH #236's 1.16 queue). `ratifiedHash` leaves out the `## Open Questions`
560
+ heading and its `deferred to v<n>` items, so `em slice defer` on a `ready-to-implement` +
561
+ `ratifiedBy:` or `implemented` doc appends the already-deferred item
562
+ `- [x] <question> — v<N>: <decision>; deferred to v<n> (<date>[, <by>])` to the doc — visible to
563
+ every reader of the ratified doc — and `ratifiedHash`, `--slice-ready` and `ratify`'s re-run all
564
+ stay valid. When v<n> opens as a draft — `mark-implemented` at merge, or `revise` — the item is
565
+ reopened as `- [ ] <question>` exactly as a pre-ratification deferral is. A question `em slice
566
+ defer` queued in `.event-modeling.md` under 1.16.x is still injected when the next draft opens, and
567
+ `em upgrade`'s `ratified-hash-scope` step moves any leftover into its doc. `em export` reports the
568
+ work waiting on later versions as `slice.doc.queuedForNext` (schema `1.17`). **A
556
569
  `ready-to-implement` doc with no `ratifiedBy`** is the leftover of a pre-1.15 `reratify` (which
557
570
  bumped the version and left the doc unsigned at that status); no command produces it any more and
558
571
  `em slice ratify` no longer accepts it — `em slice revise` reopens it as a `draft` at the same
@@ -1,9 +1,9 @@
1
1
  {
2
- "name": "em-1-16-1",
2
+ "name": "em-1-17-0",
3
3
  "owner": {
4
4
  "name": "Mike Key"
5
5
  },
6
- "description": "em v1.16.1: the Event Modeling skill bundle and MCP server as a Claude Code plugin.",
6
+ "description": "em v1.17.0: the Event Modeling skill bundle and MCP server as a Claude Code plugin.",
7
7
  "plugins": [
8
8
  {
9
9
  "name": "em",
@@ -73,7 +73,9 @@ export interface SliceDocExport {
73
73
  ratifiedRef: string | null;
74
74
  /** MIL-284: `sha256:<hex>` over the doc body at ratification (frontmatter `ratifiedHash:`),
75
75
  * written only by `em slice ratify` — null when absent. `--slice-ready` compares it to the
76
- * current body (`slice-ready-body-changed-since-ratification`). */
76
+ * current body (`slice-ready-body-changed-since-ratification`). Since 1.17.0 the `## Open
77
+ * Questions` heading and its `deferred to v<n>` items are outside the hash (GH #253,
78
+ * `sliceDoc.ts`'s `ratifiedBody`); a pre-1.17 whole-body hash is still accepted as intact. */
77
79
  ratifiedHash: string | null;
78
80
  /** MIL-283/284: the shipped record — `em slice mark-implemented`'s `shippedVersion:`/
79
81
  * `shippedRef:`/`shippedOn:` beside `implementedIn:`, or, for a doc shipped before em 1.15
@@ -107,14 +109,20 @@ export interface SliceDocExport {
107
109
  * differently (`--contract-change "<why>"`); null when absent. At most one of
108
110
  * `meaningConfirmed`/`contractChange` is set by em's own writers. */
109
111
  contractChange: string | null;
112
+ /** GH #260 (schema 1.18): frontmatter `reviewSkipped:` — the status `em slice ratify
113
+ * --skip-review` ratified from, when that bypass is what let the ratification through. Null
114
+ * when the ratification passed the review gate, when the doc predates 1.17, and whenever no
115
+ * doc was found. A host gate reads it to fail or warn on an unreviewed ratification. */
116
+ reviewSkipped: string | null;
110
117
  /** MIL-266: the doc's authored `### Scenario:` blocks (catalog/scenarios.ts), each as
111
118
  * `{ title, given, when, then }` string arrays, in document order. Null when the doc has no
112
119
  * well-formed block (every 1.13-style doc) or isn't found / usable. */
113
120
  scenarios: Scenario[] | null;
114
- /** GH #236: how many questions `em slice defer` has QUEUED for this slice's next version
115
- * (`.event-modeling.md` parking lot, catalog/deferQueue.ts) — known work for v<version+1> that
116
- * a ratified/shipped doc could not take without breaking its sign-off. 0 when none, when the
117
- * state file is absent, and whenever no doc was found. */
121
+ /** Known work waiting on a later version of this slice: the doc's `## Open Questions` items
122
+ * deferred to a version past `version` (GH #253, `countDeferredBeyond`), plus any question
123
+ * GH #236's 1.16 state-file queue still holds for v<version+1> (catalog/deferQueue.ts) until
124
+ * `em upgrade`'s `ratified-hash-scope` step or the next `revise`/`mark-implemented` drains it.
125
+ * 0 when none, and whenever no doc was found. */
118
126
  queuedForNext: number;
119
127
  }
120
128
  export interface SliceDocJoinResult {
@@ -35,6 +35,7 @@
35
35
  // one) to tell "extra" from "dangling" from "unratified". It reuses `NOTE_SLICE_PATH` and
36
36
  // `resolveCrossCandidate` below rather than re-deriving the ratification predicate.
37
37
  import { queuedCount } from "./deferQueue.js";
38
+ import { countDeferredBeyond } from "./sliceDoc.js";
38
39
  import { parseScenarios } from "./scenarios.js";
39
40
  import { continuationOf } from "../model/continuation.js";
40
41
  import { makeDiag } from "../model/rules.js";
@@ -83,6 +84,7 @@ const EMPTY_CONTENT = {
83
84
  conformedOn: null,
84
85
  meaningConfirmed: false,
85
86
  contractChange: null,
87
+ reviewSkipped: null,
86
88
  scenarios: null,
87
89
  queuedForNext: 0,
88
90
  };
@@ -204,8 +206,11 @@ function foundDoc(path, parsed, baseDir, docKey) {
204
206
  conformedOn: parsed.conformedOn,
205
207
  meaningConfirmed: parsed.meaningConfirmed,
206
208
  contractChange: parsed.contractChange,
209
+ reviewSkipped: parsed.reviewSkipped,
207
210
  scenarios: scenariosOf(parsed.body),
208
- queuedForNext: queuedCount(baseDir, docKey, parsed.version),
211
+ // GH #253: the doc carries its own deferrals now; the state-file count is the 1.16 queue's
212
+ // leftovers until `em upgrade` (or the next `revise`/`mark-implemented`) drains them.
213
+ queuedForNext: countDeferredBeyond(parsed.body, parsed.version) + queuedCount(baseDir, docKey, parsed.version),
209
214
  };
210
215
  }
211
216
  function scenariosOf(body) {
@@ -1 +1 @@
1
- {"version":3,"file":"docJoin.js","sourceRoot":"","sources":["../../src/catalog/docJoin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"docJoin.js","sourceRoot":"","sources":["../../src/catalog/docJoin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { NormalizedModel } from "../model/model.js";
2
+ import { RefsResult } from "../model/refs.js";
3
+ import { Diagnostic } from "../model/validate.js";
4
+ /** One `slice-body-changed-since-ratification` error per doc whose body no longer matches its
5
+ * recorded `ratifiedHash` (in either scope). `baseDir` is the `.em` file's directory. Docs with
6
+ * no hash are not reported — `--slice-ready --require-ratified-hash` (GH #256) is that check. */
7
+ export declare function validateSignedBodies(model: NormalizedModel, refs: RefsResult, baseDir: string): Diagnostic[];
@@ -0,0 +1,29 @@
1
+ import { pushDiag } from "../model/rules.js";
2
+ import { readSliceDoc } from "./readSliceDoc.js";
3
+ import { hasUsableFrontmatter, ratifiedHashScope } from "./sliceDoc.js";
4
+ /** One `slice-body-changed-since-ratification` error per doc whose body no longer matches its
5
+ * recorded `ratifiedHash` (in either scope). `baseDir` is the `.em` file's directory. Docs with
6
+ * no hash are not reported — `--slice-ready --require-ratified-hash` (GH #256) is that check. */
7
+ export function validateSignedBodies(model, refs, baseDir) {
8
+ const diags = [];
9
+ const seen = new Set();
10
+ model.slices.forEach((slice, i) => {
11
+ const sliceKey = refs.sliceKeys[i];
12
+ const doc = readSliceDoc(baseDir, sliceKey);
13
+ if (!doc || !hasUsableFrontmatter(doc) || doc.ratifiedHash === null)
14
+ return;
15
+ if (seen.has(sliceKey))
16
+ return;
17
+ seen.add(sliceKey);
18
+ if (ratifiedHashScope(doc.raw, doc.ratifiedHash) !== "mismatch")
19
+ return;
20
+ pushDiag(diags, "slice-body-changed-since-ratification", {
21
+ message: `slice "${sliceKey}"'s doc slices/${sliceKey}.md (status: ${doc.status ?? "(none)"}, v${doc.version ?? "?"}) was edited after ratification — ` +
22
+ "body no longer matches ratifiedHash; revert the edit, or open the next version (`em slice revise`) and re-ratify",
23
+ line: slice.line,
24
+ refs: [sliceKey],
25
+ });
26
+ });
27
+ return diags;
28
+ }
29
+ //# sourceMappingURL=signedBodyValidate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signedBodyValidate.js","sourceRoot":"","sources":["../../src/catalog/signedBodyValidate.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAExE;;kGAEkG;AAClG,MAAM,UAAU,oBAAoB,CAAC,KAAsB,EAAE,IAAgB,EAAE,OAAe;IAC5F,MAAM,KAAK,GAAiB,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,YAAY,KAAK,IAAI;YAAE,OAAO;QAC5E,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO;QAC/B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACnB,IAAI,iBAAiB,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,YAAY,CAAC,KAAK,UAAU;YAAE,OAAO;QACxE,QAAQ,CAAC,KAAK,EAAE,uCAAuC,EAAE;YACvD,OAAO,EACL,UAAU,QAAQ,kBAAkB,QAAQ,gBAAgB,GAAG,CAAC,MAAM,IAAI,QAAQ,MAAM,GAAG,CAAC,OAAO,IAAI,GAAG,oCAAoC;gBAC9I,kHAAkH;YACpH,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,CAAC,QAAQ,CAAC;SACjB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC"}