@milehimikey/em 1.8.0 → 1.9.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 (127) hide show
  1. package/.claude/skills/event-modeling/SKILL.md +58 -404
  2. package/.claude/skills/event-modeling-conform/SKILL.md +77 -0
  3. package/.claude/skills/{event-modeling → event-modeling-conform}/reference/conform.md +39 -13
  4. package/.claude/skills/event-modeling-design/SKILL.md +139 -0
  5. package/.claude/skills/event-modeling-discover/SKILL.md +89 -0
  6. package/.claude/skills/{event-modeling → event-modeling-discover}/reference/extract.md +3 -2
  7. package/.claude/skills/event-modeling-implement/SKILL.md +40 -0
  8. package/.claude/skills/{event-modeling → event-modeling-implement}/reference/implement.md +3 -2
  9. package/.claude/skills/event-modeling-review/SKILL.md +58 -0
  10. package/.claude/skills/{event-modeling → event-modeling-shared}/reference/em-dsl.md +128 -84
  11. package/.claude/skills/{event-modeling → event-modeling-shared}/reference/methodology.md +6 -5
  12. package/.claude/skills/event-modeling-shared/reference/operating-principles.md +147 -0
  13. package/.claude/skills/{event-modeling → event-modeling-shared}/templates/model-readme.md +2 -2
  14. package/.claude/skills/{event-modeling → event-modeling-shared}/templates/slice.md +51 -8
  15. package/README.md +24 -4
  16. package/dist/catalog/build.js +9 -0
  17. package/dist/catalog/build.js.map +1 -1
  18. package/dist/catalog/docJoin.d.ts +15 -0
  19. package/dist/catalog/docJoin.js +8 -0
  20. package/dist/catalog/docJoin.js.map +1 -1
  21. package/dist/catalog/modelCollisionValidate.d.ts +22 -0
  22. package/dist/catalog/modelCollisionValidate.js +67 -0
  23. package/dist/catalog/modelCollisionValidate.js.map +1 -0
  24. package/dist/catalog/orphanedSliceDocValidate.d.ts +11 -0
  25. package/dist/catalog/orphanedSliceDocValidate.js +98 -0
  26. package/dist/catalog/orphanedSliceDocValidate.js.map +1 -0
  27. package/dist/catalog/sliceDoc.d.ts +15 -0
  28. package/dist/catalog/sliceDoc.js +18 -0
  29. package/dist/catalog/sliceDoc.js.map +1 -1
  30. package/dist/cli/changelogBuild.d.ts +12 -0
  31. package/dist/cli/changelogBuild.js +89 -0
  32. package/dist/cli/changelogBuild.js.map +1 -0
  33. package/dist/cli/ciInit.d.ts +42 -0
  34. package/dist/cli/ciInit.js +298 -0
  35. package/dist/cli/ciInit.js.map +1 -0
  36. package/dist/cli/conformSupersede.d.ts +32 -0
  37. package/dist/cli/conformSupersede.js +102 -0
  38. package/dist/cli/conformSupersede.js.map +1 -0
  39. package/dist/cli/coverage.d.ts +17 -10
  40. package/dist/cli/coverage.js +61 -16
  41. package/dist/cli/coverage.js.map +1 -1
  42. package/dist/cli/frontmatterSurgery.d.ts +28 -0
  43. package/dist/cli/frontmatterSurgery.js +66 -0
  44. package/dist/cli/frontmatterSurgery.js.map +1 -0
  45. package/dist/cli/markImplemented.js +6 -45
  46. package/dist/cli/markImplemented.js.map +1 -1
  47. package/dist/cli/ratify.d.ts +41 -0
  48. package/dist/cli/ratify.js +151 -0
  49. package/dist/cli/ratify.js.map +1 -0
  50. package/dist/cli/reratify.d.ts +33 -0
  51. package/dist/cli/reratify.js +137 -0
  52. package/dist/cli/reratify.js.map +1 -0
  53. package/dist/cli/skillCheck.d.ts +6 -0
  54. package/dist/cli/skillCheck.js +46 -0
  55. package/dist/cli/skillCheck.js.map +1 -1
  56. package/dist/cli/skillDirs.d.ts +15 -0
  57. package/dist/cli/skillDirs.js +34 -0
  58. package/dist/cli/skillDirs.js.map +1 -0
  59. package/dist/cli/skillSync.d.ts +10 -0
  60. package/dist/cli/skillSync.js +15 -0
  61. package/dist/cli/skillSync.js.map +1 -1
  62. package/dist/cli/sliceIndex.d.ts +3 -0
  63. package/dist/cli/sliceIndex.js +6 -2
  64. package/dist/cli/sliceIndex.js.map +1 -1
  65. package/dist/cli/sliceLink.d.ts +52 -0
  66. package/dist/cli/sliceLink.js +152 -0
  67. package/dist/cli/sliceLink.js.map +1 -0
  68. package/dist/cli/status.d.ts +261 -0
  69. package/dist/cli/status.js +536 -0
  70. package/dist/cli/status.js.map +1 -0
  71. package/dist/cli/usageLog.d.ts +75 -0
  72. package/dist/cli/usageLog.js +193 -0
  73. package/dist/cli/usageLog.js.map +1 -0
  74. package/dist/cli.js +501 -130
  75. package/dist/cli.js.map +1 -1
  76. package/dist/emit/diffJson.d.ts +9 -1
  77. package/dist/emit/diffJson.js +44 -1
  78. package/dist/emit/diffJson.js.map +1 -1
  79. package/dist/emit/freshnessJson.d.ts +6 -0
  80. package/dist/emit/freshnessJson.js +24 -0
  81. package/dist/emit/freshnessJson.js.map +1 -0
  82. package/dist/emit/json.d.ts +67 -8
  83. package/dist/emit/json.js +19 -3
  84. package/dist/emit/json.js.map +1 -1
  85. package/dist/emit/statusJson.d.ts +7 -0
  86. package/dist/emit/statusJson.js +39 -0
  87. package/dist/emit/statusJson.js.map +1 -0
  88. package/dist/emit/typespec.d.ts +26 -0
  89. package/dist/emit/typespec.js +356 -0
  90. package/dist/emit/typespec.js.map +1 -0
  91. package/dist/emit/usageReportJson.d.ts +3 -0
  92. package/dist/emit/usageReportJson.js +23 -0
  93. package/dist/emit/usageReportJson.js.map +1 -0
  94. package/dist/mcp/server.d.ts +1 -1
  95. package/dist/mcp/server.js +301 -11
  96. package/dist/mcp/server.js.map +1 -1
  97. package/dist/model/rules.d.ts +13 -0
  98. package/dist/model/rules.js +20 -0
  99. package/dist/model/rules.js.map +1 -1
  100. package/dist/model/validate.js +9 -1
  101. package/dist/model/validate.js.map +1 -1
  102. package/dist/parser/ast.d.ts +6 -0
  103. package/dist/parser/parser.js +20 -6
  104. package/dist/parser/parser.js.map +1 -1
  105. package/dist/render/drawNotes.d.ts +11 -1
  106. package/dist/render/drawNotes.js +20 -2
  107. package/dist/render/drawNotes.js.map +1 -1
  108. package/dist/render/render.js +31 -6
  109. package/dist/render/render.js.map +1 -1
  110. package/dist/render/serve.js +4 -0
  111. package/dist/render/serve.js.map +1 -1
  112. package/dist/render/sliceOverlay.d.ts +7 -2
  113. package/dist/render/sliceOverlay.js +19 -7
  114. package/dist/render/sliceOverlay.js.map +1 -1
  115. package/dist/render/sliceStatus.d.ts +7 -3
  116. package/dist/render/sliceStatus.js +21 -14
  117. package/dist/render/sliceStatus.js.map +1 -1
  118. package/dist/render/viewerHtml.js +1 -1
  119. package/dist/render/viewerHtml.js.map +1 -1
  120. package/dist/templates.d.ts +2 -2
  121. package/dist/templates.js +5 -5
  122. package/dist/util/markers.d.ts +16 -4
  123. package/dist/util/markers.js +23 -10
  124. package/dist/util/markers.js.map +1 -1
  125. package/package.json +2 -1
  126. /package/.claude/skills/{event-modeling → event-modeling-shared}/templates/conformance-report.md +0 -0
  127. /package/.claude/skills/{event-modeling → event-modeling-shared}/templates/state.md +0 -0
@@ -3,8 +3,11 @@
3
3
  // line "every INV-n has a test that cites its ID" — until now a pure honor system, since no `em`
4
4
  // command related a slice doc's invariant IDs to a test suite. Both sides are stable strings
5
5
  // (the doc's `INV-*` tokens, a test file's source text), so the citation check is deterministic
6
- // and grep-shaped: extract every invariant ID a slice doc's body mentions, then scan a test tree
7
- // for lines that cite it.
6
+ // and grep-shaped: extract every invariant ID a slice doc's own Invariants/Delta sections define
7
+ // (MIL-149: not every ID its prose merely mentions — a doc narratively citing another slice's ID
8
+ // doesn't own it; MIL-155: including a citation embedded inside those very sections, e.g. an
9
+ // Invariants bullet's explanation pointing at a sibling slice's ID), then scan a test tree for
10
+ // lines that cite it.
8
11
  //
9
12
  // Deliberately a *second*, independent reader of doc bodies, alongside `em export`'s doc join
10
13
  // (docJoin.ts, MIL-91) — not a change to it. `em export`'s frontmatter-only contract is
@@ -28,31 +31,73 @@ import { join } from "node:path";
28
31
  import { resolveSliceDocJoin } from "../catalog/docJoin.js";
29
32
  import { readSliceDoc } from "../catalog/readSliceDoc.js";
30
33
  import { walkDir } from "../util/walkDir.js";
31
- /** The stable INV token format, scanned across a slice doc's whole body (not just the
32
- * `## Invariants / Business Rules` section — a `## Delta` section's Added/Modified/Renamed
33
- * requirement IDs are just as citable, see templates/slice.md). `INV-` then one or more
34
- * alphanumeric/hyphen segments — matches both `INV-1`/`INV-2` (the template's bare numbering)
35
- * and `INV-CHK-4`/`INV-CHK-3a` (the per-slice mnemonic style reference/conform.md's own example
36
- * uses). Exported so tests can assert against the exact grammar. */
34
+ /** The stable INV token format. `INV-` then one or more alphanumeric/hyphen segments — matches
35
+ * both `INV-1`/`INV-2` (the template's bare numbering) and `INV-CHK-4`/`INV-CHK-3a` (the
36
+ * per-slice mnemonic style reference/conform.md's own example uses). Exported so tests can
37
+ * assert against the exact grammar. */
37
38
  export const INV_TOKEN_RE = /\bINV-[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*\b/g;
39
+ /** Headings whose content *defines* (or, for `## Delta`, legitimately re-declares) an invariant
40
+ * ID for the slice doc it appears in — `## Invariants / Business Rules` itself, and `## Delta`'s
41
+ * Added/Modified/Renamed requirement subsections, which introduce/rename IDs "from Invariants
42
+ * below" on re-ratification (see templates/slice.md). Every other section — Intent, Scenarios,
43
+ * Trigger & Actor, Dependencies & Read Models Affected, Open Questions, ... — is prose that may
44
+ * narratively *cite* another slice's ID without this doc owning it (MIL-149: such a mention was
45
+ * being cross-credited to the citing slice's own coverage ledger). */
46
+ const OWNERSHIP_HEADING_RE = /^##\s+(?:Invariants(?:\s*\/\s*Business Rules)?|Delta)\s*$/i;
47
+ /** A line contributes INV tokens only when it's *structural* — a top-level bullet/list item
48
+ * (`- ...` / `* ...`, no leading indentation) or a subheading (`### ...` and deeper, since only
49
+ * `#`/`##` toggles `inOwnershipSection` above) — never an indented continuation line wrapping a
50
+ * multi-line bullet, nor a standalone prose paragraph with no bullet marker (MIL-155). Every
51
+ * cross-credit MIL-149 missed turned out to have exactly this shape: a slice's own Invariants
52
+ * bullet legitimately explains its rule across several wrapped lines, and a later wrapped line
53
+ * names a sibling slice's ID for context — e.g. `request-payment`'s `INV-RP-1` bullet wraps onto
54
+ * a line citing `payments-to-request`'s `INV-PTR-2` by way of explaining the exactly-once
55
+ * mechanism. The bullet's own *opening* line is structural and trusted for every ID it mentions
56
+ * (this also covers `## Delta`'s Renamed bullets, which legitimately declare two IDs — old and
57
+ * new — on one line, and its `**MODIFIED (...):** INV-X — ...` bullets, whose bold label isn't
58
+ * itself an ID); each wrapped continuation line is prose and contributes nothing. The indentation
59
+ * test also covers MIL-156's blessed nested-elaboration-bullet shape: `templates/slice.md`'s
60
+ * Invariants section now suggests a rule statement's optional rationale/edge-case detail go on
61
+ * its own indented sub-bullet (` - {{...}}`) rather than run on into the rule sentence, purely
62
+ * for HTML-render readability — that sub-bullet is indented, so it's already excluded here the
63
+ * same as any other continuation line, and never contributes (or steals) an ID. */
64
+ const STRUCTURAL_LINE_RE = /^(?:[-*]\s|#{3,6}\s)/;
38
65
  /** Statuses `reference/implement.md`'s coverage gate applies to — a slice hasn't reached the
39
66
  * point of needing test citations before `ready-to-implement`, and stays in scope forever after
40
67
  * once `implemented` (tests shouldn't regress away from citing an invariant just because the
41
68
  * slice shipped). Anything else (`draft`, `reviewed`, or no doc at all) is out of scope. */
42
69
  const IN_SCOPE_STATUSES = new Set(["ready-to-implement", "implemented"]);
43
70
  /**
44
- * Extract every distinct `INV-*` token from a slice doc's body text, in first-occurrence order
45
- * (a rule stated once in `## Invariants` and mentioned again in a later `## Delta` section dedupes
46
- * to its first appearance — order is for stable, readable output, not a claim about which mention
47
- * is canonical).
71
+ * Extract every distinct `INV-*` token this slice doc *defines*, in first-occurrence order (a
72
+ * rule stated once in `## Invariants` and re-declared in a later `## Delta` section dedupes to
73
+ * its first appearance — order is for stable, readable output, not a claim about which mention is
74
+ * canonical). Scoped to `OWNERSHIP_HEADING_RE`'s sections only, so a doc's prose narratively
75
+ * citing another slice's ID elsewhere (Dependencies, Open Questions, ...) doesn't cross-credit
76
+ * that ID as this slice's own (MIL-149) — the section ends at the next `#`/`##` heading or EOF,
77
+ * same boundary rule sliceDoc.ts's countOpenQuestions() uses, so a `### Added`/`#### Requirement`
78
+ * subheading under `## Delta` stays in scope while a sibling `## Scenarios` does not. Within that
79
+ * scope, only `STRUCTURAL_LINE_RE`'s bullet/subheading lines contribute — MIL-155 — so a wrapped
80
+ * continuation line that legitimately *cites* a sibling slice's ID while explaining this doc's own
81
+ * (e.g. an Invariants bullet's exactly-once rule wrapping onto a line naming another slice's
82
+ * queue-draining ID) doesn't cross-credit that citation just because it sits inside the ownership
83
+ * section too.
48
84
  */
49
85
  export function extractInvariantIds(body) {
50
86
  const seen = new Set();
51
87
  const ids = [];
52
- for (const m of body.matchAll(INV_TOKEN_RE)) {
53
- if (!seen.has(m[0])) {
54
- seen.add(m[0]);
55
- ids.push(m[0]);
88
+ let inOwnershipSection = false;
89
+ for (const line of body.split(/\r?\n/)) {
90
+ if (/^#{1,2}\s/.test(line)) {
91
+ inOwnershipSection = OWNERSHIP_HEADING_RE.test(line);
92
+ continue;
93
+ }
94
+ if (!inOwnershipSection || !STRUCTURAL_LINE_RE.test(line))
95
+ continue;
96
+ for (const m of line.matchAll(INV_TOKEN_RE)) {
97
+ if (!seen.has(m[0])) {
98
+ seen.add(m[0]);
99
+ ids.push(m[0]);
100
+ }
56
101
  }
57
102
  }
58
103
  return ids;
@@ -1 +1 @@
1
- {"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/cli/coverage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/cli/coverage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /** A field line's matched span within a frontmatter `inner` string: `key[:]<ws>` prefix
2
+ * (preserved verbatim on write) plus the value text that follows, lowercase-key-matched the
3
+ * same way sliceDoc.ts's own parser folds keys for lookup. Column-0 only — same grammar as
4
+ * sliceDoc.ts's `^([A-Za-z][\w-]*):\s*(.*)$`, so this never matches an indented/list-style line
5
+ * the parser wouldn't treat as a field either. */
6
+ export declare function fieldLineRegex(key: string): RegExp;
7
+ /** Strip a value the same way sliceDoc.ts's splitFrontmatter does when reading (surrounding
8
+ * quotes, then blank-after-trim collapses to "absent") — used here only to classify a *current*
9
+ * field value for an idempotent/refusal guard, matching what the parser would have reported for
10
+ * the same text. */
11
+ export declare function normalizeFieldValue(raw: string | undefined): string | null;
12
+ /** Same anchor as `fieldLineRegex`, but captures through the line's own trailing EOL (or
13
+ * end-of-string, for a field that happens to be the frontmatter's last line) so a match can be
14
+ * spliced out ENTIRELY — key, value, and terminator — rather than just replaced. Used by
15
+ * `em slice reratify` (reratify.ts) to drop a now-stale `ratifiedBy:`/`ratifiedOn:` pair: those
16
+ * fields describe who signed off the PRIOR version, and silently leaving them in place would
17
+ * make a fresh version look already ratified. */
18
+ export declare function fieldLineWithEolRegex(key: string): RegExp;
19
+ /** Byte offsets of the frontmatter block's inner lines (between the two `---` fences), located
20
+ * by walking lines with `indexOf` rather than `split(/\r?\n/)` — a rewrite can't afford the
21
+ * line-ending normalization a split/join would silently perform across the WHOLE file the
22
+ * moment it's written back (fine for a read-only parse, not for a surgical rewrite that must
23
+ * preserve the body byte-for-byte). `null` when there's no well-formed leading `---`/`---`
24
+ * fence, mirroring sliceDoc.ts's own "unterminated fence = no frontmatter" treatment. */
25
+ export declare function locateFrontmatterInner(markdown: string): {
26
+ innerStart: number;
27
+ innerEnd: number;
28
+ } | null;
@@ -0,0 +1,66 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Shared primitives for surgical in-place slice-doc frontmatter edits — extracted from
3
+ // `markImplemented.ts` (MIL-103) when `ratify.ts` (MIL-165) needed the exact same "find one
4
+ // field line's byte span, replace only that span, copy everything else through verbatim"
5
+ // discipline. Both commands share the same non-negotiable contract: a parse+re-serialize
6
+ // through sliceDoc.ts's own (deliberately read-only) parser would silently drop comments, key
7
+ // order, spacing, and every field the command isn't allowed to touch — see markImplemented.ts's
8
+ // module header for the full rationale, which applies unchanged here.
9
+ //
10
+ // Pure, fs-free — callers own reading/writing the file, same split as everywhere else in `em`.
11
+ /** A field line's matched span within a frontmatter `inner` string: `key[:]<ws>` prefix
12
+ * (preserved verbatim on write) plus the value text that follows, lowercase-key-matched the
13
+ * same way sliceDoc.ts's own parser folds keys for lookup. Column-0 only — same grammar as
14
+ * sliceDoc.ts's `^([A-Za-z][\w-]*):\s*(.*)$`, so this never matches an indented/list-style line
15
+ * the parser wouldn't treat as a field either. */
16
+ export function fieldLineRegex(key) {
17
+ // `[^\r\n]*` (not a lazy `.*?` + `\r?$`) deliberately -- JS regex `$`/multiline line-terminator
18
+ // semantics treat a lone `\r` as its own line boundary, which makes a trailing-`\r?$` anchor
19
+ // ambiguous on CRLF input. Excluding \r/\n from the value class sidesteps that entirely: the
20
+ // match always stops at the first \r or \n, full stop, no boundary-matching subtlety involved.
21
+ return new RegExp(`^(${key}[ \\t]*:[ \\t]*)([^\\r\\n]*)`, "im");
22
+ }
23
+ /** Strip a value the same way sliceDoc.ts's splitFrontmatter does when reading (surrounding
24
+ * quotes, then blank-after-trim collapses to "absent") — used here only to classify a *current*
25
+ * field value for an idempotent/refusal guard, matching what the parser would have reported for
26
+ * the same text. */
27
+ export function normalizeFieldValue(raw) {
28
+ if (raw === undefined)
29
+ return null;
30
+ const v = raw.trim().replace(/^["']|["']$/g, "");
31
+ return v === "" ? null : v;
32
+ }
33
+ /** Same anchor as `fieldLineRegex`, but captures through the line's own trailing EOL (or
34
+ * end-of-string, for a field that happens to be the frontmatter's last line) so a match can be
35
+ * spliced out ENTIRELY — key, value, and terminator — rather than just replaced. Used by
36
+ * `em slice reratify` (reratify.ts) to drop a now-stale `ratifiedBy:`/`ratifiedOn:` pair: those
37
+ * fields describe who signed off the PRIOR version, and silently leaving them in place would
38
+ * make a fresh version look already ratified. */
39
+ export function fieldLineWithEolRegex(key) {
40
+ return new RegExp(`^${key}[ \\t]*:[ \\t]*[^\\r\\n]*\\r?\\n?`, "im");
41
+ }
42
+ /** Byte offsets of the frontmatter block's inner lines (between the two `---` fences), located
43
+ * by walking lines with `indexOf` rather than `split(/\r?\n/)` — a rewrite can't afford the
44
+ * line-ending normalization a split/join would silently perform across the WHOLE file the
45
+ * moment it's written back (fine for a read-only parse, not for a surgical rewrite that must
46
+ * preserve the body byte-for-byte). `null` when there's no well-formed leading `---`/`---`
47
+ * fence, mirroring sliceDoc.ts's own "unterminated fence = no frontmatter" treatment. */
48
+ export function locateFrontmatterInner(markdown) {
49
+ if (!/^---[ \t]*\r?\n/.test(markdown))
50
+ return null;
51
+ const innerStart = markdown.indexOf("\n") + 1;
52
+ let pos = innerStart;
53
+ while (pos <= markdown.length) {
54
+ const nl = markdown.indexOf("\n", pos);
55
+ const lineEnd = nl === -1 ? markdown.length : nl;
56
+ const line = markdown.slice(pos, lineEnd);
57
+ if (/^---[ \t]*\r?$/.test(line)) {
58
+ return { innerStart, innerEnd: pos };
59
+ }
60
+ if (nl === -1)
61
+ break;
62
+ pos = nl + 1;
63
+ }
64
+ return null;
65
+ }
66
+ //# sourceMappingURL=frontmatterSurgery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatterSurgery.js","sourceRoot":"","sources":["../../src/cli/frontmatterSurgery.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,uFAAuF;AACvF,4FAA4F;AAC5F,yFAAyF;AACzF,yFAAyF;AACzF,8FAA8F;AAC9F,gGAAgG;AAChG,sEAAsE;AACtE,EAAE;AACF,+FAA+F;AAE/F;;;;mDAImD;AACnD,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,gGAAgG;IAChG,6FAA6F;IAC7F,6FAA6F;IAC7F,+FAA+F;IAC/F,OAAO,IAAI,MAAM,CAAC,KAAK,GAAG,8BAA8B,EAAE,IAAI,CAAC,CAAC;AAClE,CAAC;AAED;;;qBAGqB;AACrB,MAAM,UAAU,mBAAmB,CAAC,GAAuB;IACzD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IACjD,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED;;;;;kDAKkD;AAClD,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAC/C,OAAO,IAAI,MAAM,CAAC,IAAI,GAAG,mCAAmC,EAAE,IAAI,CAAC,CAAC;AACtE,CAAC;AAED;;;;;0FAK0F;AAC1F,MAAM,UAAU,sBAAsB,CAAC,QAAgB;IACrD,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9C,IAAI,GAAG,GAAG,UAAU,CAAC;IACrB,OAAO,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC9B,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACvC,MAAM,OAAO,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC1C,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;QACvC,CAAC;QACD,IAAI,EAAE,KAAK,CAAC,CAAC;YAAE,MAAM;QACrB,GAAG,GAAG,EAAE,GAAG,CAAC,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -23,54 +23,15 @@
23
23
  // `- **Status:** ...` / `- **Implemented in:** ...` bullet dialect; this module targets the
24
24
  // canonical frontmatter dialect (MIL-86) instead, and folds in the note-binding resolution the
25
25
  // bridge's caller (`mark-implemented.ts`) did via a separate `em export` shell-out.
26
+ //
27
+ // The three primitives above (`fieldLineRegex`/`normalizeFieldValue`/`locateFrontmatterInner`)
28
+ // now live in `./frontmatterSurgery.js` (MIL-165) — `ratify.ts` needs the exact same span-finding
29
+ // discipline for its own `status`/`ratifiedBy`/`ratifiedOn` edit, so they moved out to a shared
30
+ // module rather than being copy-pasted a second time.
26
31
  import { readFileSync, writeFileSync } from "node:fs";
27
32
  import { join } from "node:path";
28
33
  import { resolveSliceDocJoin } from "../catalog/docJoin.js";
29
- /** A field line's matched span within a frontmatter `inner` string: `key[:]<ws>` prefix
30
- * (preserved verbatim on write) plus the value text that follows, lowercase-key-matched the
31
- * same way sliceDoc.ts's own parser folds keys for lookup. Column-0 only — same grammar as
32
- * sliceDoc.ts's `^([A-Za-z][\w-]*):\s*(.*)$`, so this never matches an indented/list-style line
33
- * the parser wouldn't treat as a field either. */
34
- function fieldLineRegex(key) {
35
- // `[^\r\n]*` (not a lazy `.*?` + `\r?$`) deliberately -- JS regex `$`/multiline line-terminator
36
- // semantics treat a lone `\r` as its own line boundary, which makes a trailing-`\r?$` anchor
37
- // ambiguous on CRLF input. Excluding \r/\n from the value class sidesteps that entirely: the
38
- // match always stops at the first \r or \n, full stop, no boundary-matching subtlety involved.
39
- return new RegExp(`^(${key}[ \\t]*:[ \\t]*)([^\\r\\n]*)`, "im");
40
- }
41
- /** Strip a value the same way sliceDoc.ts's splitFrontmatter does when reading (surrounding
42
- * quotes, then blank-after-trim collapses to "absent") — used here only to classify the
43
- * *current* implementedIn value for the idempotent/refusal guard, matching what the parser
44
- * would have reported for the same text. */
45
- function normalizeFieldValue(raw) {
46
- if (raw === undefined)
47
- return null;
48
- const v = raw.trim().replace(/^["']|["']$/g, "");
49
- return v === "" ? null : v;
50
- }
51
- /** Byte offsets of the frontmatter block's inner lines (between the two `---` fences), located
52
- * by walking lines with `indexOf` rather than `split(/\r?\n/)` — see the module header for why
53
- * a rewrite can't afford the line-ending normalization a split/join would silently perform.
54
- * `null` when there's no well-formed leading `---`/`---` fence, mirroring sliceDoc.ts's own
55
- * "unterminated fence = no frontmatter" treatment. */
56
- function locateFrontmatterInner(markdown) {
57
- if (!/^---[ \t]*\r?\n/.test(markdown))
58
- return null;
59
- const innerStart = markdown.indexOf("\n") + 1;
60
- let pos = innerStart;
61
- while (pos <= markdown.length) {
62
- const nl = markdown.indexOf("\n", pos);
63
- const lineEnd = nl === -1 ? markdown.length : nl;
64
- const line = markdown.slice(pos, lineEnd);
65
- if (/^---[ \t]*\r?$/.test(line)) {
66
- return { innerStart, innerEnd: pos };
67
- }
68
- if (nl === -1)
69
- break;
70
- pos = nl + 1;
71
- }
72
- return null;
73
- }
34
+ import { fieldLineRegex, locateFrontmatterInner, normalizeFieldValue } from "./frontmatterSurgery.js";
74
35
  /**
75
36
  * Pure text transform: flips `status:` to `implemented` and sets `implementedIn:` to `prUrl` in
76
37
  * `raw`'s frontmatter block. Idempotent (re-applying the same URL is a no-op, `changed: false`,
@@ -1 +1 @@
1
- {"version":3,"file":"markImplemented.js","sourceRoot":"","sources":["../../src/cli/markImplemented.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"markImplemented.js","sourceRoot":"","sources":["../../src/cli/markImplemented.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { NormalizedModel } from "../model/model.js";
2
+ import { RefsResult } from "../model/refs.js";
3
+ /** The status this command flips a slice doc to — the handoff gate
4
+ * (docs/process.md#what-ratified-means): contracts/invariants agreed, open questions resolved
5
+ * or deferred, ready for an implementing agent or engineer to pick up. */
6
+ export declare const RATIFIED_STATUS = "ready-to-implement";
7
+ export type ApplyRatifyResult = {
8
+ ok: true;
9
+ content: string;
10
+ changed: boolean;
11
+ } | {
12
+ ok: false;
13
+ message: string;
14
+ };
15
+ /**
16
+ * Pure text transform: flips `status:` to `ready-to-implement` and sets `ratifiedBy:`/
17
+ * `ratifiedOn:` in `raw`'s frontmatter block. Idempotent (re-applying the same by/on pair once
18
+ * already ratified is a no-op, `changed: false`, `content` returned byte-identical to `raw`);
19
+ * refuses (`ok: false`) rather than silently overwrite provenance when the doc is already
20
+ * `status: ready-to-implement` with a *different* recorded ratifier/date — mirroring
21
+ * `applyImplementedFrontmatter`'s refusal to overwrite a different `implementedIn`. There is no
22
+ * such refusal when `status` isn't already the target: re-ratifying a slice that has since moved
23
+ * on (e.g. back from `implemented` after a version bump — docs/slice-doc-schema.md#status-under-
24
+ * re-ratification) is the ordinary, expected use of this command, so it always applies cleanly.
25
+ * No fs access — the caller reads/writes; see `runRatify` below.
26
+ */
27
+ export declare function applyRatifyFrontmatter(raw: string, ratifiedBy: string, ratifiedOn: string): ApplyRatifyResult;
28
+ export type RunRatifyResult = {
29
+ ok: true;
30
+ path: string;
31
+ changed: boolean;
32
+ } | {
33
+ ok: false;
34
+ message: string;
35
+ };
36
+ /**
37
+ * Resolves `sliceKey` to its bound doc via the same note-binding join `mark-implemented`/
38
+ * `--slice-ready`/`em export` use (MIL-121 cross-binding included), then reads/applies/writes
39
+ * it. `baseDir` is the `.em` file's directory, same convention every doc/note path in `em` uses.
40
+ */
41
+ export declare function runRatify(model: NormalizedModel, refs: RefsResult, baseDir: string, sliceKey: string, ratifiedBy: string, ratifiedOn: string): RunRatifyResult;
@@ -0,0 +1,151 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // `em slice ratify` (MIL-165): makes "who ratified, and when" a first-class recorded fact
3
+ // instead of an unnamed edit anyone with commit access could make. Flips `status:
4
+ // ready-to-implement` and sets `ratifiedBy:`/`ratifiedOn:` on the slice doc resolved from the
5
+ // key via the SAME note-binding resolution `mark-implemented`/`--slice-ready`/`em export` use
6
+ // (catalog/docJoin.ts's resolveSliceDocJoin) — same shape and idempotency discipline as
7
+ // `em slice mark-implemented` (MIL-103, markImplemented.ts), mirrored deliberately so the two
8
+ // lifecycle-flip commands (ratify at handoff, mark-implemented at merge) read as one family.
9
+ //
10
+ // Write strategy: the same surgical index-math splicing markImplemented.ts uses, via the shared
11
+ // primitives in ./frontmatterSurgery.js — never a parse+re-serialize (sliceDoc.ts's own parser
12
+ // is deliberately read-only and drops everything not in its `SliceDoc` shape). Everything
13
+ // outside the edited value spans — the body, `version:`, `implementedIn:`, the lineage/`covers`
14
+ // keys, and (best-effort) the file's own line-ending style — is copied through verbatim.
15
+ //
16
+ // `ratifiedBy`/`ratifiedOn` are additive, optional frontmatter keys (docs/slice-doc-schema.md):
17
+ // omitting them is not an error to any existing `em` command (the "unknown keys are captured,
18
+ // never read, never a warning" contract already covers a doc that predates this feature), and
19
+ // this command is the only thing that ever writes them — same "one write path" discipline
20
+ // `mark-implemented` holds for `implementedIn`.
21
+ import { readFileSync, writeFileSync } from "node:fs";
22
+ import { join } from "node:path";
23
+ import { resolveSliceDocJoin } from "../catalog/docJoin.js";
24
+ import { fieldLineRegex, locateFrontmatterInner, normalizeFieldValue } from "./frontmatterSurgery.js";
25
+ import { isValidDateString } from "./stateFile.js";
26
+ /** The status this command flips a slice doc to — the handoff gate
27
+ * (docs/process.md#what-ratified-means): contracts/invariants agreed, open questions resolved
28
+ * or deferred, ready for an implementing agent or engineer to pick up. */
29
+ export const RATIFIED_STATUS = "ready-to-implement";
30
+ /**
31
+ * Pure text transform: flips `status:` to `ready-to-implement` and sets `ratifiedBy:`/
32
+ * `ratifiedOn:` in `raw`'s frontmatter block. Idempotent (re-applying the same by/on pair once
33
+ * already ratified is a no-op, `changed: false`, `content` returned byte-identical to `raw`);
34
+ * refuses (`ok: false`) rather than silently overwrite provenance when the doc is already
35
+ * `status: ready-to-implement` with a *different* recorded ratifier/date — mirroring
36
+ * `applyImplementedFrontmatter`'s refusal to overwrite a different `implementedIn`. There is no
37
+ * such refusal when `status` isn't already the target: re-ratifying a slice that has since moved
38
+ * on (e.g. back from `implemented` after a version bump — docs/slice-doc-schema.md#status-under-
39
+ * re-ratification) is the ordinary, expected use of this command, so it always applies cleanly.
40
+ * No fs access — the caller reads/writes; see `runRatify` below.
41
+ */
42
+ export function applyRatifyFrontmatter(raw, ratifiedBy, ratifiedOn) {
43
+ const trimmedBy = ratifiedBy.trim();
44
+ if (!trimmedBy)
45
+ return { ok: false, message: "a ratifier name is required (--by)" };
46
+ // Refuse control characters (including an embedded \r/\n, which could splice a multi-line
47
+ // value into the frontmatter and corrupt the fence) — unlike mark-implemented's PR-URL guard,
48
+ // internal whitespace is fine: a person's name legitimately contains spaces ("Alice Smith").
49
+ if (/[\x00-\x1f\x7f]/.test(trimmedBy)) {
50
+ return { ok: false, message: "ratifier name must not contain control characters" };
51
+ }
52
+ if (!isValidDateString(ratifiedOn)) {
53
+ return { ok: false, message: `invalid date "${ratifiedOn}" — expected YYYY-MM-DD` };
54
+ }
55
+ const range = locateFrontmatterInner(raw);
56
+ if (!range)
57
+ return { ok: false, message: "no frontmatter block found" };
58
+ const inner = raw.slice(range.innerStart, range.innerEnd);
59
+ const statusMatch = fieldLineRegex("status").exec(inner);
60
+ if (!statusMatch)
61
+ return { ok: false, message: "no `status:` field found in frontmatter" };
62
+ const byMatch = fieldLineRegex("ratifiedBy").exec(inner);
63
+ const onMatch = fieldLineRegex("ratifiedOn").exec(inner);
64
+ const currentStatus = normalizeFieldValue(statusMatch[2])?.toLowerCase() ?? null;
65
+ const currentBy = byMatch ? normalizeFieldValue(byMatch[2]) : null;
66
+ const currentOn = onMatch ? normalizeFieldValue(onMatch[2]) : null;
67
+ if (currentStatus === RATIFIED_STATUS && currentBy !== null && currentOn !== null) {
68
+ if (currentBy === trimmedBy && currentOn === ratifiedOn) {
69
+ return { ok: true, content: raw, changed: false }; // idempotent no-op
70
+ }
71
+ return {
72
+ ok: false,
73
+ message: `already ratified by ${currentBy} on ${currentOn} — refusing to overwrite with ` +
74
+ `${trimmedBy} on ${ratifiedOn}`,
75
+ };
76
+ }
77
+ // Match the file's own line-ending style for any freshly-inserted line, same trick
78
+ // markImplemented.ts uses: on a CRLF doc, the text right after the status line's match starts
79
+ // with the "\r\n" that used to terminate it, so reusing it keeps a new line consistent with
80
+ // its neighbors instead of being the one bare-LF line in an otherwise-CRLF file.
81
+ const afterStatus = inner.slice(statusMatch.index + statusMatch[0].length);
82
+ const eol = afterStatus.startsWith("\r\n") ? "\r\n" : "\n";
83
+ // Whichever of ratifiedBy/ratifiedOn have no existing line get folded directly into the status
84
+ // edit's replacement text (inserted right after the new status value) rather than added as
85
+ // separate zero-length "insert" edits — simpler and unambiguous to splice than reasoning about
86
+ // an insert-edit's index coinciding with an adjacent replace-edit's span.
87
+ const missingLines = [];
88
+ if (!byMatch)
89
+ missingLines.push(`ratifiedBy: ${trimmedBy}`);
90
+ if (!onMatch)
91
+ missingLines.push(`ratifiedOn: ${ratifiedOn}`);
92
+ const newStatusText = `${statusMatch[1]}${RATIFIED_STATUS}`;
93
+ const statusNext = missingLines.length > 0 ? `${newStatusText}${eol}${missingLines.join(eol)}` : newStatusText;
94
+ // Apply from the highest index first so an earlier edit's index stays valid — same convention
95
+ // markImplemented.ts uses. Each present match (status always, ratifiedBy/ratifiedOn only when
96
+ // an existing line was found) is replaced independently of the others' positions, so this is
97
+ // safe even when the frontmatter's keys are out of the usual order.
98
+ const edits = [
99
+ { index: statusMatch.index, oldLen: statusMatch[0].length, next: statusNext },
100
+ ];
101
+ if (byMatch)
102
+ edits.push({ index: byMatch.index, oldLen: byMatch[0].length, next: `${byMatch[1]}${trimmedBy}` });
103
+ if (onMatch)
104
+ edits.push({ index: onMatch.index, oldLen: onMatch[0].length, next: `${onMatch[1]}${ratifiedOn}` });
105
+ edits.sort((a, b) => b.index - a.index);
106
+ let updatedInner = inner;
107
+ for (const edit of edits) {
108
+ updatedInner = updatedInner.slice(0, edit.index) + edit.next + updatedInner.slice(edit.index + edit.oldLen);
109
+ }
110
+ const content = raw.slice(0, range.innerStart) + updatedInner + raw.slice(range.innerEnd);
111
+ return { ok: true, content, changed: true };
112
+ }
113
+ /**
114
+ * Resolves `sliceKey` to its bound doc via the same note-binding join `mark-implemented`/
115
+ * `--slice-ready`/`em export` use (MIL-121 cross-binding included), then reads/applies/writes
116
+ * it. `baseDir` is the `.em` file's directory, same convention every doc/note path in `em` uses.
117
+ */
118
+ export function runRatify(model, refs, baseDir, sliceKey, ratifiedBy, ratifiedOn) {
119
+ const sliceIndex = refs.sliceKeys.indexOf(sliceKey);
120
+ if (sliceIndex === -1) {
121
+ return { ok: false, message: `no slice with export key "${sliceKey}" in this model` };
122
+ }
123
+ const slice = model.slices[sliceIndex];
124
+ const { doc } = resolveSliceDocJoin(slice, sliceKey, baseDir, (id) => refs.refById.get(id));
125
+ if (doc.reason === "no-doc-bound") {
126
+ return {
127
+ ok: false,
128
+ message: `slice "${sliceKey}" has no doc bound via \`note "slices/${sliceKey}.md"\` — bind a slice doc before ratifying it`,
129
+ };
130
+ }
131
+ if (doc.reason === "binding-missing-file") {
132
+ return { ok: false, message: `slice "${sliceKey}" notes "${doc.path}" but no such file exists` };
133
+ }
134
+ if (doc.reason === "frontmatter-invalid") {
135
+ return {
136
+ ok: false,
137
+ message: `slice doc "${doc.path}" has missing or invalid frontmatter — run \`em validate\` for details`,
138
+ };
139
+ }
140
+ const absPath = join(baseDir, doc.path);
141
+ const raw = readFileSync(absPath, "utf8");
142
+ const result = applyRatifyFrontmatter(raw, ratifiedBy, ratifiedOn);
143
+ if (!result.ok) {
144
+ return { ok: false, message: `${doc.path}: ${result.message}` };
145
+ }
146
+ if (result.changed) {
147
+ writeFileSync(absPath, result.content, "utf8");
148
+ }
149
+ return { ok: true, path: doc.path, changed: result.changed };
150
+ }
151
+ //# sourceMappingURL=ratify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ratify.js","sourceRoot":"","sources":["../../src/cli/ratify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { NormalizedModel } from "../model/model.js";
2
+ import { RefsResult } from "../model/refs.js";
3
+ export type ApplyReratifyResult = {
4
+ ok: true;
5
+ content: string;
6
+ newVersion: number;
7
+ } | {
8
+ ok: false;
9
+ message: string;
10
+ };
11
+ /**
12
+ * Pure text transform: bumps `version:` by 1 and flips `status:` to `ready-to-implement` in
13
+ * `raw`'s frontmatter block, clearing any `ratifiedBy:`/`ratifiedOn:` lines found (see module
14
+ * header). Refuses (`ok: false`) unless the doc's CURRENT `status:` is exactly `implemented` —
15
+ * see module header for why this precondition (not idempotent-no-op) is the right refusal
16
+ * shape here. No fs access — the caller reads/writes; see `runReratify` below.
17
+ */
18
+ export declare function applyReratifyFrontmatter(raw: string): ApplyReratifyResult;
19
+ export type RunReratifyResult = {
20
+ ok: true;
21
+ path: string;
22
+ newVersion: number;
23
+ } | {
24
+ ok: false;
25
+ message: string;
26
+ };
27
+ /**
28
+ * Resolves `sliceKey` to its bound doc via the same note-binding join `mark-implemented`/
29
+ * `ratify`/`--slice-ready`/`em export` use (MIL-121 cross-binding included), then reads/applies/
30
+ * writes it. `baseDir` is the `.em` file's directory, same convention every doc/note path in
31
+ * `em` uses.
32
+ */
33
+ export declare function runReratify(model: NormalizedModel, refs: RefsResult, baseDir: string, sliceKey: string): RunReratifyResult;