@milehimikey/em 1.14.1 → 1.15.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 +3 -3
- package/.claude/skills/event-modeling-conform/SKILL.md +1 -1
- package/.claude/skills/event-modeling-design/SKILL.md +29 -18
- package/.claude/skills/event-modeling-discover/SKILL.md +1 -1
- package/.claude/skills/event-modeling-engagement/SKILL.md +54 -54
- package/.claude/skills/event-modeling-engagement/reference/engagement.md +5 -19
- package/.claude/skills/event-modeling-implement/SKILL.md +1 -1
- package/.claude/skills/event-modeling-implement/reference/implement.md +29 -23
- package/.claude/skills/event-modeling-review/SKILL.md +13 -3
- package/.claude/skills/event-modeling-shared/reference/em-dsl.md +230 -227
- package/.claude/skills/event-modeling-shared/reference/operating-principles.md +3 -3
- package/.claude/skills/event-modeling-shared/reference/slice-doc-schema.md +58 -27
- package/.claude/skills/event-modeling-shared/templates/constitution.md +5 -7
- package/.claude-plugin/marketplace.json +2 -2
- package/README.md +12 -0
- package/dist/catalog/docJoin.d.ts +17 -1
- package/dist/catalog/docJoin.js +7 -1
- package/dist/catalog/docJoin.js.map +1 -1
- package/dist/catalog/driftSignal.d.ts +16 -12
- package/dist/catalog/driftSignal.js +14 -9
- package/dist/catalog/driftSignal.js.map +1 -1
- package/dist/catalog/sliceDoc.d.ts +51 -0
- package/dist/catalog/sliceDoc.js +47 -0
- package/dist/catalog/sliceDoc.js.map +1 -1
- package/dist/catalog/sliceReadyValidate.js +12 -0
- package/dist/catalog/sliceReadyValidate.js.map +1 -1
- package/dist/cli/conformScope.d.ts +4 -0
- package/dist/cli/conformScope.js +2 -2
- package/dist/cli/conformScope.js.map +1 -1
- package/dist/cli/coverage.js +7 -3
- package/dist/cli/coverage.js.map +1 -1
- package/dist/cli/defer.d.ts +61 -2
- package/dist/cli/defer.js +204 -23
- package/dist/cli/defer.js.map +1 -1
- package/dist/cli/engagement.d.ts +13 -5
- package/dist/cli/engagement.js +26 -19
- package/dist/cli/engagement.js.map +1 -1
- package/dist/cli/findings.d.ts +2 -2
- package/dist/cli/findings.js +2 -2
- package/dist/cli/frontmatterSurgery.d.ts +3 -3
- package/dist/cli/frontmatterSurgery.js +3 -3
- package/dist/cli/frontmatterSurgery.js.map +1 -1
- package/dist/cli/markImplemented.d.ts +20 -9
- package/dist/cli/markImplemented.js +112 -14
- package/dist/cli/markImplemented.js.map +1 -1
- package/dist/cli/ratify.d.ts +36 -6
- package/dist/cli/ratify.js +130 -35
- package/dist/cli/ratify.js.map +1 -1
- package/dist/cli/review.js +3 -3
- package/dist/cli/review.js.map +1 -1
- package/dist/cli/revise.d.ts +57 -0
- package/dist/cli/revise.js +207 -0
- package/dist/cli/revise.js.map +1 -0
- package/dist/cli/sliceConform.d.ts +4 -3
- package/dist/cli/sliceConform.js +29 -12
- package/dist/cli/sliceConform.js.map +1 -1
- package/dist/cli/status.d.ts +8 -0
- package/dist/cli/status.js +7 -4
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/upgrade.js +7 -4
- package/dist/cli/upgrade.js.map +1 -1
- package/dist/cli.js +118 -77
- package/dist/cli.js.map +1 -1
- package/dist/emit/json.d.ts +1 -1
- package/dist/emit/json.js +13 -1
- package/dist/emit/json.js.map +1 -1
- package/dist/emit/statusJson.d.ts +1 -1
- package/dist/emit/statusJson.js +4 -1
- package/dist/emit/statusJson.js.map +1 -1
- package/dist/mcp/server.js +5 -5
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/rules.d.ts +8 -0
- package/dist/model/rules.js +8 -0
- package/dist/model/rules.js.map +1 -1
- package/dist/model/sliceDocIndex.d.ts +3 -0
- package/dist/model/sliceDocIndex.js +5 -4
- package/dist/model/sliceDocIndex.js.map +1 -1
- package/dist/templates.d.ts +1 -1
- package/dist/templates.js +5 -7
- package/dist/templates.js.map +1 -1
- package/package.json +2 -2
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/shared/reference/em-dsl.md +230 -227
- package/plugin/shared/reference/operating-principles.md +3 -3
- package/plugin/shared/reference/slice-doc-schema.md +58 -27
- package/plugin/shared/templates/constitution.md +5 -7
- package/plugin/skills/conform/SKILL.md +1 -1
- package/plugin/skills/design/SKILL.md +29 -18
- package/plugin/skills/discover/SKILL.md +1 -1
- package/plugin/skills/engagement/SKILL.md +54 -54
- package/plugin/skills/engagement/reference/engagement.md +5 -19
- package/plugin/skills/event-modeling/SKILL.md +3 -3
- package/plugin/skills/implement/SKILL.md +1 -1
- package/plugin/skills/implement/reference/implement.md +29 -23
- package/plugin/skills/review/SKILL.md +13 -3
- package/dist/cli/reratify.d.ts +0 -58
- package/dist/cli/reratify.js +0 -238
- package/dist/cli/reratify.js.map +0 -1
|
@@ -119,12 +119,12 @@ including sessions started from bare `/event-modeling`.
|
|
|
119
119
|
- **Version rule: never bump a draft's `version:` on edit.** A `draft`/`reviewed` doc is edited
|
|
120
120
|
in place. Check the release state with `em status <model>.em --json`: the model is
|
|
121
121
|
**pre-release** when its `modelVersion` entry has `design: null` and
|
|
122
|
-
`slices.byStatus.
|
|
122
|
+
`slices.byStatus.shipped === 0`. Pre-release: never run `em slice revise`; edit
|
|
123
123
|
`draft`/`reviewed` docs in place and leave `version:` as it is. A pre-release doc that is
|
|
124
124
|
already ratified (`ready-to-implement` with `ratifiedBy`) carries a human sign-off: STOP,
|
|
125
125
|
record the needed change as an open question, and let the ratifier decide. Released (either
|
|
126
|
-
condition false): changing
|
|
127
|
-
(see `event-modeling-design`).
|
|
126
|
+
condition false): changing a shipped or ratified doc goes through `em slice revise`, which
|
|
127
|
+
opens the next version as a `draft` (see `event-modeling-design`).
|
|
128
128
|
- **Pre-commit check (STOP on any finding).** Stage the session's files, then run both:
|
|
129
129
|
1. `em system scope --staged` from the repository root. Any `seam-crossing` error → STOP:
|
|
130
130
|
unstage the other model's files and record a seam change request instead.
|
|
@@ -67,8 +67,13 @@ 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
|
-
| `
|
|
71
|
-
| `
|
|
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`) |
|
|
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 |
|
|
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
|
+
| `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
|
+
| `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) |
|
|
72
77
|
| `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[]` |
|
|
73
78
|
| `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 |
|
|
74
79
|
| `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 |
|
|
@@ -245,7 +250,7 @@ straight through to the originating slice's own doc, exactly the way a ratified
|
|
|
245
250
|
binding resolves a covered slice — same `doc.found`/`status`/`driftSignal`, plus a
|
|
246
251
|
`continuationOf: <originating-key>` field naming why. `em export`, `em status`, `em coverage`,
|
|
247
252
|
`em slice index`, `em catalog`, and the render pipeline's Slice Status legend all resolve a
|
|
248
|
-
continuation slice this way; `em slice ratify`/`review`/`
|
|
253
|
+
continuation slice this way; `em slice ratify`/`review`/`revise`/`mark-implemented` and
|
|
249
254
|
`em slice new --wire` refuse on one outright, naming the originating slice to act on instead —
|
|
250
255
|
a continuation slice has no status/ratification of its own to flip.
|
|
251
256
|
|
|
@@ -482,7 +487,7 @@ prior one — exactly the ambiguity a live, current-version-only section avoids.
|
|
|
482
487
|
**Deferral marker (MIL-275).** A question this version will not answer is not left `- [ ]` and
|
|
483
488
|
not deleted: `em slice defer` checks it and rewrites it as `- [x] <original> — v<current>:
|
|
484
489
|
<decision>; deferred to v<n> (<date>[, <by>])`. The `deferred to v<n>` marker is what
|
|
485
|
-
`em slice
|
|
490
|
+
`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
|
|
486
491
|
`- [ ] <original>`, so the question must be resolved or re-deferred before `--slice-ready` passes
|
|
487
492
|
again. The prune rule above does not apply to a deferred item before v<n> (it stays as the
|
|
488
493
|
record); once reopened it is an ordinary open question.
|
|
@@ -497,26 +502,51 @@ actually happened on re-ratification).
|
|
|
497
502
|
|
|
498
503
|
## `status` under re-ratification
|
|
499
504
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
`
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
shipped
|
|
508
|
-
|
|
509
|
-
|
|
505
|
+
Since 1.15.0 (MIL-283) two separate facts live in the frontmatter, and every reader knows which
|
|
506
|
+
one it is asking about:
|
|
507
|
+
|
|
508
|
+
- **`status` is the working state** of the doc's current `version:` — `draft`, `reviewed`,
|
|
509
|
+
`ready-to-implement`, `implemented`.
|
|
510
|
+
- **The shipped record is what is in production**: `shippedVersion:`/`shippedRef:`/`shippedOn:`
|
|
511
|
+
(written by `em slice mark-implemented`, MIL-284) together with `implementedIn:`. For a doc
|
|
512
|
+
shipped before 1.15 — no `shippedVersion:` — the read-both rule applies: `status: implemented`
|
|
513
|
+
means "shipped at the current `version:`". The one function that answers "has a version of this
|
|
514
|
+
slice shipped, and which" is `shippedRecordOf()` (`src/catalog/sliceDoc.ts`); `em export`
|
|
515
|
+
publishes its answer as `slice.doc.shipped`.
|
|
516
|
+
|
|
517
|
+
So a shipped slice can be a `draft` again. `em slice revise <key>`
|
|
518
|
+
([cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-slice-revise-file-slice-key)) opens v<N+1> as `status: draft`, bumps
|
|
519
|
+
`version:`, clears the prior version's review and sign-off, and leaves `implementedIn`/`shipped*`
|
|
520
|
+
alone — v<N> stays shipped. `em slice mark-implemented` does the same automatically at merge when a
|
|
521
|
+
question was deferred to v<N+1> (`em slice defer`), so known work is on the list the moment the
|
|
522
|
+
previous version lands. Version 2 then takes both human gates like version 1 did: `em slice review
|
|
523
|
+
--by`, then `em slice ratify --by` (which records a fresh `ratifiedRef`/`ratifiedHash`).
|
|
524
|
+
|
|
525
|
+
The deliberate mismatch — `version: 2` open while `implementedIn`/`shippedVersion` still name v1's
|
|
526
|
+
work — is not staleness, it's the **drift signal**: `em export`'s `slice.doc.driftSignal` is
|
|
527
|
+
`"unpropagated-delta"` whenever `version` is past the shipped version (MIL-85/283), and the
|
|
528
|
+
event-modeling skill's `conform` phase reads it as "a delta hasn't shipped yet", not a fresh finding
|
|
529
|
+
against the still-live v1 code. `em validate`'s frontmatter-coherence check (MIL-85) never flags it;
|
|
530
|
+
only a shipped slice with no `implementedIn` link at all is checkable incoherence
|
|
531
|
+
(`implemented-without-link`); see
|
|
510
532
|
[validation.md#frontmatter-coherence](https://github.com/milehimikey/em/blob/main/docs/validation.md#frontmatter-coherence).
|
|
511
533
|
|
|
512
|
-
**
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
534
|
+
**Which readers decide on the shipped record, not `status`** (MIL-283): `em status`'s
|
|
535
|
+
`byStatus.shipped` count and its conformance scope, `em coverage --strict`'s default scope, `em
|
|
536
|
+
conform-scope` / `em conform-supersede`'s in-scope slices, `em slice conform` (legal when shipped;
|
|
537
|
+
`conformedVersion:` is the **shipped** version), the engagement Ledger's inferred `merged` and its
|
|
538
|
+
outside-upstream hold, `em upgrade`'s pre-release signal, `em slice ratify`'s upstream advisory, and
|
|
539
|
+
`driftSignal`. `byStatus.implemented`, the render/legend colouring and `--slice-ready` still read the
|
|
540
|
+
working `status` — that is what they are about.
|
|
541
|
+
|
|
542
|
+
**A ratified version that never shipped** (`status: ready-to-implement` with `ratifiedBy:` set — a
|
|
543
|
+
gap answered mid-build) is revised the same way: `draft`, `version + 1`, sign-off cleared; the
|
|
544
|
+
ratification of v<N> is withdrawn and nothing shipped, so no shipped record is written. **A
|
|
545
|
+
`ready-to-implement` doc with no `ratifiedBy`** is the leftover of a pre-1.15 `reratify` (which
|
|
546
|
+
bumped the version and left the doc unsigned at that status); no command produces it any more and
|
|
547
|
+
`em slice ratify` no longer accepts it — `em slice revise` reopens it as a `draft` at the same
|
|
548
|
+
version, and the normal road follows. `draft`/`reviewed` docs are not ratified and are simply
|
|
549
|
+
edited; `revise` refuses them ("the next version is already open").
|
|
520
550
|
|
|
521
551
|
Pair a re-ratification with a `## Delta` section (see
|
|
522
552
|
[Delta section: grammar and lifecycle](#delta-section-grammar-and-lifecycle) above) recording
|
|
@@ -526,10 +556,11 @@ the ratified change in typed operation blocks, so it's reviewable without openin
|
|
|
526
556
|
see [cli.md#em-ledger-file](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-ledger-file)) checks that `version:` and a slice doc's
|
|
527
557
|
content (body + lineage refs) always change together across two git revisions — a version bump
|
|
528
558
|
with no real content change, or a content change with no version bump, is a ledger bug.
|
|
529
|
-
It **deliberately excludes `status`/`implementedIn`**
|
|
530
|
-
the reason this section explains: a
|
|
531
|
-
`implementedIn` naming prior work, with no version bump
|
|
532
|
-
the comparison would flag every ordinary lifecycle
|
|
559
|
+
It **deliberately excludes `status`/`implementedIn`** (and the `shipped*` keys) from what counts
|
|
560
|
+
as "content" for exactly the reason this section explains: a lifecycle transition legitimately
|
|
561
|
+
moves `status` and leaves `implementedIn`/`shippedVersion` naming prior work, with no version bump
|
|
562
|
+
of its own — including those fields in the comparison would flag every ordinary lifecycle
|
|
563
|
+
transition as a false positive.
|
|
533
564
|
|
|
534
565
|
## Unknown keys
|
|
535
566
|
|
|
@@ -563,7 +594,7 @@ legacy form; they're frontmatter-only from the day they were introduced.
|
|
|
563
594
|
- [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-render-file) — slice status colors
|
|
564
595
|
- [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-catalog-files) — pattern / doc lookup
|
|
565
596
|
- [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-slice-ratify-file-slice-key---by-name) — `em slice ratify`, the mechanized ratification act (`ratifiedBy`/`ratifiedOn`, schema `1.8`, MIL-165)
|
|
566
|
-
- [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-slice-
|
|
597
|
+
- [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-slice-revise-file-slice-key) — `em slice revise`, which opens the next version as a draft (the successor of `reratify`)
|
|
567
598
|
- [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-export-file) — the `em export` join (`slice.pattern`/`slice.doc`, schema `1.4`, MIL-91), including `owner`/`tracking` (schema `1.9`, MIL-171)
|
|
568
599
|
- [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-diff-old-new) — the `em diff` lineage annotation (schema `1.6`, MIL-84)
|
|
569
600
|
- [validation.md#lineage](https://github.com/milehimikey/em/blob/main/docs/validation.md#lineage) — `em validate`'s lineage-ref resolution (MIL-84)
|
|
@@ -23,9 +23,9 @@ NAMED human and an ISO date, hand-filled at sign-off (no `em` command writes thi
|
|
|
23
23
|
unratified, says so, and does not proceed on unilateral style or stack decisions for a first slice.
|
|
24
24
|
|
|
25
25
|
`em status` reports this document as present or absent per model — existence only. em never reads
|
|
26
|
-
or validates its content, and the CLI parses nothing here.
|
|
26
|
+
or validates its content, and the CLI parses nothing here. Two lines are read as plain text by
|
|
27
27
|
the engagement skill and its sub-agents, so keep their exact shape: `- **Test command:**` (the
|
|
28
|
-
validator)
|
|
28
|
+
validator) and `- **Agent models:**` (the engagement skill). In a spec-kit
|
|
29
29
|
project they merge under the same headings in `.specify/memory/constitution.md`.
|
|
30
30
|
-->
|
|
31
31
|
|
|
@@ -120,11 +120,9 @@ it is silent, these apply.
|
|
|
120
120
|
amend** — a `covers:` doc ships as one PR for both keys; a read model is one doc, so a later
|
|
121
121
|
`again` instance is a continuation of the doc that first declared it, not a PR of its own. See
|
|
122
122
|
the agent guide's §5/§10.
|
|
123
|
-
- **Merge strategy:** merge
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
Keep this exact line: it is the only value the engagement skill accepts, and it refuses to run
|
|
127
|
-
without it.}}
|
|
123
|
+
- **Merge strategy:** {{squash | merge commit | rebase — the project's own choice. Every slice PR
|
|
124
|
+
is cut from and targets `main` (implement contract §8 rule 2), so no PR ever depends on
|
|
125
|
+
another and any strategy works; em reads nothing from this line.}}
|
|
128
126
|
- **Agent models:** implementer=sonnet, validator=sonnet, reviewer=sonnet, critic=opus
|
|
129
127
|
{{**Which model runs each em sub-agent?** Keep this exact line shape, with the defaults shown or
|
|
130
128
|
your own choices. The critic must run on a different model from the implementer; `critic=codex`
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "em-1-
|
|
2
|
+
"name": "em-1-15-0",
|
|
3
3
|
"owner": {
|
|
4
4
|
"name": "Mike Key"
|
|
5
5
|
},
|
|
6
|
-
"description": "em v1.
|
|
6
|
+
"description": "em v1.15.0: the Event Modeling skill bundle and MCP server as a Claude Code plugin.",
|
|
7
7
|
"plugins": [
|
|
8
8
|
{
|
|
9
9
|
"name": "em",
|
package/README.md
CHANGED
|
@@ -21,6 +21,18 @@ Requires Node ≥ 18. SVG, PNG, and PDF rendering are all fully self-contained (
|
|
|
21
21
|
as bundled WebAssembly); nothing else to install. Only rarer formats (ps, eps, ...) need an
|
|
22
22
|
optional system dependency — see [docs/dependencies.md](docs/dependencies.md).
|
|
23
23
|
|
|
24
|
+
**Working in a team, or across several repos?** Pin `em` per project instead, so every
|
|
25
|
+
contributor, agent and CI job runs the same version — with [mise](https://mise.jdx.dev) it's one
|
|
26
|
+
line and needs no `package.json`:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
mise use npm:@milehimikey/em@1.14.1 # writes the pin to mise.toml; bare `em` now resolves to it
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Pair it with the Claude Code plugin pin (below) and the CLI, the skills and the MCP server are all
|
|
33
|
+
on one version. See [docs/ai-workflow.md](docs/ai-workflow.md#pinning-the-cli-to-the-same-version)
|
|
34
|
+
for the full motion, including the `npx` route for repos without mise.
|
|
35
|
+
|
|
24
36
|
## Quickstart
|
|
25
37
|
|
|
26
38
|
```bash
|
|
@@ -3,7 +3,8 @@ import { NormalizedModel, Slice } from "../model/model.js";
|
|
|
3
3
|
import { RefsResult } from "../model/refs.js";
|
|
4
4
|
import { Diagnostic } from "../model/validate.js";
|
|
5
5
|
import { DriftSignalKind } from "./driftSignal.js";
|
|
6
|
-
import { SliceDoc, SliceRef } from "./sliceDoc.js";
|
|
6
|
+
import { ShippedRecord, SliceDoc, SliceRef } from "./sliceDoc.js";
|
|
7
|
+
export type { ShippedRecord } from "./sliceDoc.js";
|
|
7
8
|
export declare const NOTE_SLICE_PATH: RegExp;
|
|
8
9
|
/** One cross-binding candidate's resolution against `sliceKey`'s ratification requirement:
|
|
9
10
|
* the target file doesn't exist, exists but its frontmatter isn't usable, exists and is usable
|
|
@@ -66,6 +67,21 @@ export interface SliceDocExport {
|
|
|
66
67
|
/** MIL-165: when this doc was ratified (frontmatter `ratifiedOn:`, `YYYY-MM-DD`), written only
|
|
67
68
|
* by `em slice ratify` — null when absent, same as `ratifiedBy`. */
|
|
68
69
|
ratifiedOn: string | null;
|
|
70
|
+
/** MIL-284: the commit (full sha) whose tree holds the ratified body (frontmatter
|
|
71
|
+
* `ratifiedRef:`), written only by `em slice ratify` inside a git repository — null when
|
|
72
|
+
* absent (ratified before em 1.15, by hand, or outside git). The ratified content's address. */
|
|
73
|
+
ratifiedRef: string | null;
|
|
74
|
+
/** MIL-284: `sha256:<hex>` over the doc body at ratification (frontmatter `ratifiedHash:`),
|
|
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`). */
|
|
77
|
+
ratifiedHash: string | null;
|
|
78
|
+
/** MIL-283/284: the shipped record — `em slice mark-implemented`'s `shippedVersion:`/
|
|
79
|
+
* `shippedRef:`/`shippedOn:` beside `implementedIn:`, or, for a doc shipped before em 1.15
|
|
80
|
+
* (no `shippedVersion:`), the `status: implemented` it carries (read-both rule,
|
|
81
|
+
* `shippedRecordOf`). Null when nothing has shipped. THIS — not `status` — is what every
|
|
82
|
+
* lifecycle reader decides on since 1.15.0: `status` is the working state, and a shipped slice
|
|
83
|
+
* can be `draft` again while its earlier version stays shipped. */
|
|
84
|
+
shipped: ShippedRecord | null;
|
|
69
85
|
/** MIL-171: who (a person or team) holds this slice, from frontmatter `owner:` — hand-filled,
|
|
70
86
|
* no `em` command writes it. Null when absent. */
|
|
71
87
|
owner: string | null;
|
package/dist/catalog/docJoin.js
CHANGED
|
@@ -39,7 +39,7 @@ import { continuationOf } from "../model/continuation.js";
|
|
|
39
39
|
import { makeDiag } from "../model/rules.js";
|
|
40
40
|
import { classifyImplementationDrift } from "./driftSignal.js";
|
|
41
41
|
import { readSliceDoc } from "./readSliceDoc.js";
|
|
42
|
-
import { hasUsableFrontmatter } from "./sliceDoc.js";
|
|
42
|
+
import { hasUsableFrontmatter, shippedRecordOf } from "./sliceDoc.js";
|
|
43
43
|
// Matches a `note "slices/<key>.md"` value's path shape, to pull `<key>` back out for the
|
|
44
44
|
// MIL-121 cross-binding search below (and MIL-126's mismatch sweep, catalog/noteBindingValidate.ts)
|
|
45
45
|
// — same kebab-slug grammar sliceDoc.ts's SLICE_REF uses.
|
|
@@ -72,6 +72,9 @@ const EMPTY_CONTENT = {
|
|
|
72
72
|
reviewedOn: null,
|
|
73
73
|
ratifiedBy: null,
|
|
74
74
|
ratifiedOn: null,
|
|
75
|
+
ratifiedRef: null,
|
|
76
|
+
ratifiedHash: null,
|
|
77
|
+
shipped: null,
|
|
75
78
|
owner: null,
|
|
76
79
|
tracking: null,
|
|
77
80
|
conformedVersion: null,
|
|
@@ -189,6 +192,9 @@ function foundDoc(path, parsed) {
|
|
|
189
192
|
reviewedOn: parsed.reviewedOn,
|
|
190
193
|
ratifiedBy: parsed.ratifiedBy,
|
|
191
194
|
ratifiedOn: parsed.ratifiedOn,
|
|
195
|
+
ratifiedRef: parsed.ratifiedRef,
|
|
196
|
+
ratifiedHash: parsed.ratifiedHash,
|
|
197
|
+
shipped: shippedRecordOf(parsed),
|
|
192
198
|
owner: parsed.owner,
|
|
193
199
|
tracking: parsed.tracking,
|
|
194
200
|
conformedVersion: parsed.conformedVersion,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docJoin.js","sourceRoot":"","sources":["../../src/catalog/docJoin.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,4FAA4F;AAC5F,6FAA6F;AAC7F,2FAA2F;AAC3F,4FAA4F;AAC5F,uFAAuF;AACvF,6FAA6F;AAC7F,oFAAoF;AACpF,0FAA0F;AAC1F,4FAA4F;AAC5F,EAAE;AACF,oFAAoF;AACpF,6FAA6F;AAC7F,4FAA4F;AAC5F,8FAA8F;AAC9F,wCAAwC;AACxC,EAAE;AACF,gGAAgG;AAChG,gGAAgG;AAChG,gGAAgG;AAChG,8FAA8F;AAC9F,iGAAiG;AACjG,6FAA6F;AAC7F,+FAA+F;AAC/F,iGAAiG;AACjG,6FAA6F;AAC7F,gGAAgG;AAChG,oDAAoD;AACpD,EAAE;AACF,6FAA6F;AAC7F,qEAAqE;AACrE,2FAA2F;AAC3F,4FAA4F;AAC5F,iGAAiG;AACjG,0FAA0F;AAC1F,oFAAoF;AAEpF,OAAO,EAAE,cAAc,EAAY,MAAM,gBAAgB,CAAC;AAG1D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,2BAA2B,EAAmB,MAAM,kBAAkB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAsB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"docJoin.js","sourceRoot":"","sources":["../../src/catalog/docJoin.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
import { SliceDoc } from "./sliceDoc.js";
|
|
2
2
|
export type DriftSignalKind =
|
|
3
|
-
/**
|
|
3
|
+
/** shipped, implementedIn set, the doc's version IS the shipped version and conformedVersion
|
|
4
|
+
* matches it — certified current. */
|
|
4
5
|
"in-sync"
|
|
5
|
-
/**
|
|
6
|
+
/** nothing shipped, implementedIn absent — normal pre-ship state. */
|
|
6
7
|
| "never-implemented"
|
|
7
|
-
/**
|
|
8
|
-
*
|
|
8
|
+
/** a ratified/drafted delta hasn't shipped yet: either the doc's `version:` is past the shipped
|
|
9
|
+
* version (MIL-283 — a later draft is open over a shipped version), or (pre-1.15 shape) status
|
|
10
|
+
* is off `implemented` while `implementedIn` still names the prior version's PR. Expected, not
|
|
11
|
+
* a defect: never surface this as fresh drift or a validate diagnostic. */
|
|
9
12
|
| "unpropagated-delta"
|
|
10
|
-
/**
|
|
13
|
+
/** shipped, implementedIn absent — genuine incoherence (em validate warns). */
|
|
11
14
|
| "implemented-without-link"
|
|
12
|
-
/**
|
|
13
|
-
*
|
|
14
|
-
* defect: never surface this as an `em validate` diagnostic (see
|
|
15
|
+
/** shipped, implementedIn set, the doc's version is the shipped version, but conformedVersion
|
|
16
|
+
* is absent or doesn't match — nobody has certified THIS version yet. Expected post-ship
|
|
17
|
+
* default, not a defect: never surface this as an `em validate` diagnostic (see
|
|
15
18
|
* catalog/frontmatterCoherenceValidate.ts, which only ever flags implemented-without-link). */
|
|
16
19
|
| "uncertified";
|
|
17
20
|
/**
|
|
18
|
-
* Classify a doc's
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
+
* Classify a doc's drift from its shipped record (MIL-283: `shippedRecordOf`, which reads the
|
|
22
|
+
* `shipped*` keys and, for a doc written before 1.15, `status: implemented`), its `implementedIn`,
|
|
23
|
+
* its working `version` and `conformedVersion`. Takes a `Pick` rather than the full `SliceDoc`
|
|
24
|
+
* so callers building a partial/synthetic doc (tests, future callers) don't need every field.
|
|
21
25
|
*/
|
|
22
|
-
export declare function classifyImplementationDrift(doc: Pick<SliceDoc, "status" | "implementedIn" | "version" | "conformedVersion">): DriftSignalKind;
|
|
26
|
+
export declare function classifyImplementationDrift(doc: Pick<SliceDoc, "status" | "implementedIn" | "version" | "conformedVersion" | "ratifiedRef" | "shippedVersion" | "shippedRef" | "shippedOn">): DriftSignalKind;
|
|
@@ -21,18 +21,23 @@
|
|
|
21
21
|
// reratify`) invalidates the prior certification even though `status`/`implementedIn` still read
|
|
22
22
|
// "shipped" — so this is not folded into `in-sync` and not flagged by `em validate` (same
|
|
23
23
|
// "expected, not a defect" treatment `unpropagated-delta` gets).
|
|
24
|
+
import { shippedRecordOf } from "./sliceDoc.js";
|
|
24
25
|
/**
|
|
25
|
-
* Classify a doc's
|
|
26
|
-
*
|
|
27
|
-
*
|
|
26
|
+
* Classify a doc's drift from its shipped record (MIL-283: `shippedRecordOf`, which reads the
|
|
27
|
+
* `shipped*` keys and, for a doc written before 1.15, `status: implemented`), its `implementedIn`,
|
|
28
|
+
* its working `version` and `conformedVersion`. Takes a `Pick` rather than the full `SliceDoc`
|
|
29
|
+
* so callers building a partial/synthetic doc (tests, future callers) don't need every field.
|
|
28
30
|
*/
|
|
29
31
|
export function classifyImplementationDrift(doc) {
|
|
30
32
|
const hasLink = typeof doc.implementedIn === "string" && doc.implementedIn.trim().length > 0;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
const shipped = shippedRecordOf(doc);
|
|
34
|
+
if (shipped === null)
|
|
35
|
+
return hasLink ? "unpropagated-delta" : "never-implemented";
|
|
36
|
+
if (!hasLink)
|
|
37
|
+
return "implemented-without-link";
|
|
38
|
+
// A later version is open (draft/reviewed/ready-to-implement) over the shipped one.
|
|
39
|
+
if (shipped.version !== null && doc.version !== null && doc.version > shipped.version)
|
|
40
|
+
return "unpropagated-delta";
|
|
41
|
+
return doc.conformedVersion !== null && doc.conformedVersion === shipped.version ? "in-sync" : "uncertified";
|
|
37
42
|
}
|
|
38
43
|
//# sourceMappingURL=driftSignal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driftSignal.js","sourceRoot":"","sources":["../../src/catalog/driftSignal.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,4FAA4F;AAC5F,uFAAuF;AACvF,2FAA2F;AAC3F,iGAAiG;AACjG,yFAAyF;AACzF,kCAAkC;AAClC,EAAE;AACF,6FAA6F;AAC7F,iGAAiG;AACjG,iGAAiG;AACjG,mGAAmG;AACnG,2FAA2F;AAC3F,EAAE;AACF,6FAA6F;AAC7F,gGAAgG;AAChG,mFAAmF;AACnF,8FAA8F;AAC9F,8FAA8F;AAC9F,wFAAwF;AACxF,iGAAiG;AACjG,0FAA0F;AAC1F,iEAAiE;
|
|
1
|
+
{"version":3,"file":"driftSignal.js","sourceRoot":"","sources":["../../src/catalog/driftSignal.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,4FAA4F;AAC5F,uFAAuF;AACvF,2FAA2F;AAC3F,iGAAiG;AACjG,yFAAyF;AACzF,kCAAkC;AAClC,EAAE;AACF,6FAA6F;AAC7F,iGAAiG;AACjG,iGAAiG;AACjG,mGAAmG;AACnG,2FAA2F;AAC3F,EAAE;AACF,6FAA6F;AAC7F,gGAAgG;AAChG,mFAAmF;AACnF,8FAA8F;AAC9F,8FAA8F;AAC9F,wFAAwF;AACxF,iGAAiG;AACjG,0FAA0F;AAC1F,iEAAiE;AAEjE,OAAO,EAAE,eAAe,EAAY,MAAM,eAAe,CAAC;AAqB1D;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CACzC,GAGC;IAED,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,aAAa,KAAK,QAAQ,IAAI,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7F,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,mBAAmB,CAAC;IAClF,IAAI,CAAC,OAAO;QAAE,OAAO,0BAA0B,CAAC;IAChD,oFAAoF;IACpF,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI,IAAI,GAAG,CAAC,OAAO,KAAK,IAAI,IAAI,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO;QAAE,OAAO,oBAAoB,CAAC;IACnH,OAAO,GAAG,CAAC,gBAAgB,KAAK,IAAI,IAAI,GAAG,CAAC,gBAAgB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC;AAC/G,CAAC"}
|
|
@@ -82,6 +82,25 @@ export interface SliceDoc {
|
|
|
82
82
|
* to find the ticket mirroring this slice — its export name/shape (docJoin.ts) is a
|
|
83
83
|
* cross-tool contract, not just an internal display field. */
|
|
84
84
|
tracking: string | null;
|
|
85
|
+
/** MIL-284: `ratifiedRef:` — the commit (full sha) whose tree holds the body that was ratified,
|
|
86
|
+
* written only by `em slice ratify` when the model dir is inside a git repository; null when
|
|
87
|
+
* absent (a doc ratified before em 1.15, or outside git). The ratified content's address. */
|
|
88
|
+
ratifiedRef: string | null;
|
|
89
|
+
/** MIL-284: `ratifiedHash:` — `sha256:<hex>` over the doc body at ratification (see
|
|
90
|
+
* `sliceDocBodyHash`), written only by `em slice ratify`; null when absent. Identity that
|
|
91
|
+
* needs no git: `--slice-ready` compares it to the current body
|
|
92
|
+
* (`slice-ready-body-changed-since-ratification`). */
|
|
93
|
+
ratifiedHash: string | null;
|
|
94
|
+
/** MIL-284: `shippedVersion:` — this doc's `version:` at the moment `em slice mark-implemented`
|
|
95
|
+
* recorded the merge; null when absent (shipped before em 1.15, or never). The three
|
|
96
|
+
* `shipped*` keys plus `implementedIn` are the shipped record the lifecycle's readers move to
|
|
97
|
+
* in MIL-283; here they are additive. */
|
|
98
|
+
shippedVersion: number | null;
|
|
99
|
+
/** MIL-284: `shippedRef:` — the `ratifiedRef` of the version that shipped, copied at
|
|
100
|
+
* mark-implemented time; null when the doc had none. */
|
|
101
|
+
shippedRef: string | null;
|
|
102
|
+
/** MIL-284: `shippedOn:` — `YYYY-MM-DD`, the local date mark-implemented ran; null when absent. */
|
|
103
|
+
shippedOn: string | null;
|
|
85
104
|
/** MIL-214: `conformedVersion:` — this slice's `version:` at the time a conform sweep last
|
|
86
105
|
* certified it, or null when never certified. Written only by `em slice conform`. Paired with
|
|
87
106
|
* `version` to compute `driftSignal`'s `uncertified` case (catalog/driftSignal.ts). */
|
|
@@ -155,4 +174,36 @@ export declare function hasUsableFrontmatter(doc: Pick<SliceDoc, "frontmatterPre
|
|
|
155
174
|
* starts with a letter.
|
|
156
175
|
*/
|
|
157
176
|
export declare function parseSliceRef(raw: string): SliceRef;
|
|
177
|
+
/** MIL-284/283: the shipped record — what `em slice mark-implemented` wrote at merge, or, for a
|
|
178
|
+
* doc shipped before em 1.15 (no `shippedVersion:`), what `status: implemented` meant then. */
|
|
179
|
+
export interface ShippedRecord {
|
|
180
|
+
/** The doc's `version:` when the merge was recorded (`shippedVersion:`); for a pre-1.15
|
|
181
|
+
* `implemented` doc, its current `version:` (null when that is unparseable). */
|
|
182
|
+
version: number | null;
|
|
183
|
+
/** The `ratifiedRef` that version was signed at (`shippedRef:`), or null when the doc had none. */
|
|
184
|
+
ratifiedRef: string | null;
|
|
185
|
+
/** The merged PR/commit URL — the same `implementedIn:` the doc carries at top level. */
|
|
186
|
+
implementedIn: string | null;
|
|
187
|
+
/** `YYYY-MM-DD`, the local date mark-implemented ran (`shippedOn:`), or null when absent. */
|
|
188
|
+
on: string | null;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* MIL-283: THE question every lifecycle reader asks — "has a version of this slice shipped, and
|
|
192
|
+
* which?" — answered from the shipped record, not from `status`. `status` is the WORKING state:
|
|
193
|
+
* since 1.15.0 a shipped slice can read `status: draft` again (`em slice mark-implemented` opens
|
|
194
|
+
* the next version when a question is deferred to it; `em slice revise` on demand) while its v1
|
|
195
|
+
* stays shipped. The read-both rule for docs written before 1.15.0: `status: implemented` with no
|
|
196
|
+
* `shippedVersion:` is shipped at its current `version:`. Anything else is not shipped — a
|
|
197
|
+
* `ready-to-implement` doc still carrying a prior `implementedIn:` (the 1.13–1.14 reratify
|
|
198
|
+
* state) included; `driftSignal` reads that as `unpropagated-delta`, as it always did.
|
|
199
|
+
*/
|
|
200
|
+
export declare function shippedRecordOf(doc: Pick<SliceDoc, "status" | "version" | "implementedIn" | "ratifiedRef" | "shippedVersion" | "shippedRef" | "shippedOn">): ShippedRecord | null;
|
|
201
|
+
/** MIL-284: the identity `em slice ratify` records as `ratifiedHash:` and `--slice-ready` checks
|
|
202
|
+
* against: `sha256:<hex>` over the doc BODY — everything after the closing frontmatter fence (or
|
|
203
|
+
* the whole doc when there is none), EOLs normalised to `\n` by `splitFrontmatter`'s split/join.
|
|
204
|
+
* Frontmatter is excluded on purpose: the ratify edit itself, `mark-implemented` and `conform`
|
|
205
|
+
* touch only frontmatter, without changing what was ratified. `em slice defer` is NOT in that
|
|
206
|
+
* list — it rewrites a body line (the Open Questions item), so a deferral belongs before the
|
|
207
|
+
* sign-off; after it, the hash no longer matches and `--slice-ready` says so. */
|
|
208
|
+
export declare function sliceDocBodyHash(markdown: string): string;
|
|
158
209
|
export declare function parseSliceDoc(markdown: string): SliceDoc;
|
package/dist/catalog/sliceDoc.js
CHANGED
|
@@ -66,6 +66,18 @@
|
|
|
66
66
|
// `--contract-change "<why>"` -> `contractChange: "<why>"`). Additive, tolerate-unknown-fields:
|
|
67
67
|
// absent on every doc predating this feature, and on every non-public slice ratified without
|
|
68
68
|
// either flag.
|
|
69
|
+
//
|
|
70
|
+
// `ratifiedRef`/`ratifiedHash` and `shippedVersion`/`shippedRef`/`shippedOn` (MIL-284, the
|
|
71
|
+
// additive half of MIL-283 "ratification has an address") give the two lifecycle facts an exact
|
|
72
|
+
// identity. `ratifiedRef` is the commit whose tree holds the ratified body and `ratifiedHash` the
|
|
73
|
+
// `sha256:` of that body (`sliceDocBodyHash`, below) — written only by `em slice ratify`, which
|
|
74
|
+
// refuses a doc with uncommitted changes so the ref really does hold what was signed. The
|
|
75
|
+
// `shipped*` trio is written only by `em slice mark-implemented` beside `implementedIn`: the
|
|
76
|
+
// version that shipped, the ref it was ratified at, the local date. Flat keys, not a nested
|
|
77
|
+
// block, because this parser is line-based (no yaml dependency, see above) and because every
|
|
78
|
+
// writer in cli/*.ts is a surgical single-line splice. Additive, tolerate-unknown-fields; the
|
|
79
|
+
// readers that will DECIDE on `shipped*` instead of `status` are MIL-283's breaking half.
|
|
80
|
+
import { createHash } from "node:crypto";
|
|
69
81
|
import { marked } from "marked";
|
|
70
82
|
/** Frontmatter keys docs/slice-doc-schema.md's required-vs-optional table marks
|
|
71
83
|
* required at every `status` — the mechanical basis for `frontmatter-invalid`
|
|
@@ -193,6 +205,36 @@ function splitFrontmatter(markdown) {
|
|
|
193
205
|
return { fields: new Map(), body: markdown, frontmatterPresent: false };
|
|
194
206
|
return { fields, body: lines.slice(closeIndex + 1).join("\n"), frontmatterPresent: true };
|
|
195
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* MIL-283: THE question every lifecycle reader asks — "has a version of this slice shipped, and
|
|
210
|
+
* which?" — answered from the shipped record, not from `status`. `status` is the WORKING state:
|
|
211
|
+
* since 1.15.0 a shipped slice can read `status: draft` again (`em slice mark-implemented` opens
|
|
212
|
+
* the next version when a question is deferred to it; `em slice revise` on demand) while its v1
|
|
213
|
+
* stays shipped. The read-both rule for docs written before 1.15.0: `status: implemented` with no
|
|
214
|
+
* `shippedVersion:` is shipped at its current `version:`. Anything else is not shipped — a
|
|
215
|
+
* `ready-to-implement` doc still carrying a prior `implementedIn:` (the 1.13–1.14 reratify
|
|
216
|
+
* state) included; `driftSignal` reads that as `unpropagated-delta`, as it always did.
|
|
217
|
+
*/
|
|
218
|
+
export function shippedRecordOf(doc) {
|
|
219
|
+
if (doc.shippedVersion !== null) {
|
|
220
|
+
return { version: doc.shippedVersion, ratifiedRef: doc.shippedRef, implementedIn: doc.implementedIn, on: doc.shippedOn };
|
|
221
|
+
}
|
|
222
|
+
if (doc.status === "implemented") {
|
|
223
|
+
return { version: doc.version, ratifiedRef: doc.ratifiedRef, implementedIn: doc.implementedIn, on: null };
|
|
224
|
+
}
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
/** MIL-284: the identity `em slice ratify` records as `ratifiedHash:` and `--slice-ready` checks
|
|
228
|
+
* against: `sha256:<hex>` over the doc BODY — everything after the closing frontmatter fence (or
|
|
229
|
+
* the whole doc when there is none), EOLs normalised to `\n` by `splitFrontmatter`'s split/join.
|
|
230
|
+
* Frontmatter is excluded on purpose: the ratify edit itself, `mark-implemented` and `conform`
|
|
231
|
+
* touch only frontmatter, without changing what was ratified. `em slice defer` is NOT in that
|
|
232
|
+
* list — it rewrites a body line (the Open Questions item), so a deferral belongs before the
|
|
233
|
+
* sign-off; after it, the hash no longer matches and `--slice-ready` says so. */
|
|
234
|
+
export function sliceDocBodyHash(markdown) {
|
|
235
|
+
const { body } = splitFrontmatter(markdown);
|
|
236
|
+
return `sha256:${createHash("sha256").update(body, "utf8").digest("hex")}`;
|
|
237
|
+
}
|
|
196
238
|
export function parseSliceDoc(markdown) {
|
|
197
239
|
const { fields, body, frontmatterPresent } = splitFrontmatter(markdown);
|
|
198
240
|
const legacyMatch = body.match(STATUS_LINE);
|
|
@@ -219,6 +261,11 @@ export function parseSliceDoc(markdown) {
|
|
|
219
261
|
reviewedOn: fields.get("reviewedon") ?? null,
|
|
220
262
|
ratifiedBy: fields.get("ratifiedby") ?? null,
|
|
221
263
|
ratifiedOn: fields.get("ratifiedon") ?? null,
|
|
264
|
+
ratifiedRef: fields.get("ratifiedref") ?? null,
|
|
265
|
+
ratifiedHash: fields.get("ratifiedhash") ?? null,
|
|
266
|
+
shippedVersion: parseVersion(fields.get("shippedversion")),
|
|
267
|
+
shippedRef: fields.get("shippedref") ?? null,
|
|
268
|
+
shippedOn: fields.get("shippedon") ?? null,
|
|
222
269
|
owner: fields.get("owner") ?? null,
|
|
223
270
|
tracking: fields.get("tracking") ?? null,
|
|
224
271
|
conformedVersion: parseVersion(fields.get("conformedversion")),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sliceDoc.js","sourceRoot":"","sources":["../../src/catalog/sliceDoc.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,yDAAyD;AACzD,2EAA2E;AAC3E,2EAA2E;AAC3E,8EAA8E;AAC9E,4EAA4E;AAC5E,8EAA8E;AAC9E,iEAAiE;AACjE,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,6EAA6E;AAC7E,8EAA8E;AAC9E,2EAA2E;AAC3E,yEAAyE;AACzE,EAAE;AACF,oEAAoE;AACpE,wEAAwE;AACxE,kFAAkF;AAClF,8EAA8E;AAC9E,8EAA8E;AAC9E,6EAA6E;AAC7E,EAAE;AACF,8EAA8E;AAC9E,4EAA4E;AAC5E,4EAA4E;AAC5E,8EAA8E;AAC9E,0EAA0E;AAC1E,EAAE;AACF,4EAA4E;AAC5E,4FAA4F;AAC5F,qFAAqF;AACrF,8EAA8E;AAC9E,sFAAsF;AACtF,6CAA6C;AAC7C,EAAE;AACF,6FAA6F;AAC7F,6FAA6F;AAC7F,8FAA8F;AAC9F,iGAAiG;AACjG,qFAAqF;AACrF,EAAE;AACF,6FAA6F;AAC7F,+FAA+F;AAC/F,kGAAkG;AAClG,wFAAwF;AACxF,6FAA6F;AAC7F,+EAA+E;AAC/E,uEAAuE;AACvE,EAAE;AACF,4FAA4F;AAC5F,wFAAwF;AACxF,8FAA8F;AAC9F,iGAAiG;AACjG,8FAA8F;AAC9F,4FAA4F;AAC5F,8FAA8F;AAC9F,yFAAyF;AACzF,+FAA+F;AAC/F,iGAAiG;AACjG,uEAAuE;AACvE,EAAE;AACF,sFAAsF;AACtF,6FAA6F;AAC7F,4FAA4F;AAC5F,gGAAgG;AAChG,6FAA6F;AAC7F,eAAe;
|
|
1
|
+
{"version":3,"file":"sliceDoc.js","sourceRoot":"","sources":["../../src/catalog/sliceDoc.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
import { makeDiag, pushDiag } from "../model/rules.js";
|
|
28
28
|
import { resolveSliceDocJoin } from "./docJoin.js";
|
|
29
29
|
import { readSliceDoc } from "./readSliceDoc.js";
|
|
30
|
+
import { sliceDocBodyHash } from "./sliceDoc.js";
|
|
30
31
|
import { findStructuredSectionProblems } from "./sliceSections.js";
|
|
31
32
|
import { contractStatus, slicePublicTouching } from "./apiFirst.js";
|
|
32
33
|
/** MIL-238 (briefing R10): the API-first gate's diagnostic for one slice, or null when the slice
|
|
@@ -115,6 +116,17 @@ export function validateSliceReady(model, refs, baseDir, sliceKey, contract) {
|
|
|
115
116
|
// actually supplied status/version above, not always this slice's own file.
|
|
116
117
|
const boundKey = doc.path.replace(/^slices\//, "").replace(/\.md$/, "");
|
|
117
118
|
const parsed = readSliceDoc(baseDir, boundKey);
|
|
119
|
+
// MIL-284: the ratified body has an identity now. A doc whose body moved after `em slice
|
|
120
|
+
// ratify` recorded `ratifiedHash:` is not the spec that was signed — the ratification stands
|
|
121
|
+
// on content that is gone. Only checked when a hash exists (a doc ratified before em 1.15 has
|
|
122
|
+
// none and is judged on `ratifiedBy` alone, as before) and only at ready-to-implement.
|
|
123
|
+
if (doc.status === "ready-to-implement" && doc.ratifiedHash !== null && sliceDocBodyHash(parsed.raw) !== doc.ratifiedHash) {
|
|
124
|
+
pushDiag(diags, "slice-ready-body-changed-since-ratification", {
|
|
125
|
+
message: `slice "${sliceKey}"'s doc ${doc.path} was edited after ratification (body no longer matches ratifiedHash) — revert, or re-ratify the new content`,
|
|
126
|
+
line: slice.line,
|
|
127
|
+
refs: [sliceKey],
|
|
128
|
+
});
|
|
129
|
+
}
|
|
118
130
|
if (parsed.openQuestionsUnchecked > 0) {
|
|
119
131
|
pushDiag(diags, "slice-ready-open-questions-unchecked", {
|
|
120
132
|
message: `slice "${sliceKey}" has ${parsed.openQuestionsUnchecked} of ${parsed.openQuestionsTotal} Open Question(s) unchecked`,
|