@mmnto/totem 1.14.8 → 1.14.10

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 (74) hide show
  1. package/dist/ast-grep-query.d.ts +22 -2
  2. package/dist/ast-grep-query.d.ts.map +1 -1
  3. package/dist/ast-grep-query.js +34 -5
  4. package/dist/ast-grep-query.js.map +1 -1
  5. package/dist/ast-grep-query.test.js +45 -1
  6. package/dist/ast-grep-query.test.js.map +1 -1
  7. package/dist/compile-lesson.d.ts +24 -1
  8. package/dist/compile-lesson.d.ts.map +1 -1
  9. package/dist/compile-lesson.js +131 -60
  10. package/dist/compile-lesson.js.map +1 -1
  11. package/dist/compile-lesson.test.js +283 -14
  12. package/dist/compile-lesson.test.js.map +1 -1
  13. package/dist/compile-manifest.d.ts +14 -1
  14. package/dist/compile-manifest.d.ts.map +1 -1
  15. package/dist/compile-manifest.js +107 -3
  16. package/dist/compile-manifest.js.map +1 -1
  17. package/dist/compile-manifest.test.js +123 -1
  18. package/dist/compile-manifest.test.js.map +1 -1
  19. package/dist/compile-smoke-gate.d.ts +42 -0
  20. package/dist/compile-smoke-gate.d.ts.map +1 -0
  21. package/dist/compile-smoke-gate.js +135 -0
  22. package/dist/compile-smoke-gate.js.map +1 -0
  23. package/dist/compile-smoke-gate.test.d.ts +2 -0
  24. package/dist/compile-smoke-gate.test.d.ts.map +1 -0
  25. package/dist/compile-smoke-gate.test.js +202 -0
  26. package/dist/compile-smoke-gate.test.js.map +1 -0
  27. package/dist/compiler-schema.d.ts +286 -24
  28. package/dist/compiler-schema.d.ts.map +1 -1
  29. package/dist/compiler-schema.js +128 -5
  30. package/dist/compiler-schema.js.map +1 -1
  31. package/dist/compiler-schema.test.d.ts +2 -0
  32. package/dist/compiler-schema.test.d.ts.map +1 -0
  33. package/dist/compiler-schema.test.js +263 -0
  34. package/dist/compiler-schema.test.js.map +1 -0
  35. package/dist/compiler.d.ts +22 -5
  36. package/dist/compiler.d.ts.map +1 -1
  37. package/dist/compiler.js +9 -3
  38. package/dist/compiler.js.map +1 -1
  39. package/dist/compiler.test.js +19 -5
  40. package/dist/compiler.test.js.map +1 -1
  41. package/dist/index.d.ts +3 -3
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +2 -2
  44. package/dist/index.js.map +1 -1
  45. package/dist/ledger.d.ts +1 -1
  46. package/dist/lesson-pattern.d.ts +64 -1
  47. package/dist/lesson-pattern.d.ts.map +1 -1
  48. package/dist/lesson-pattern.js +153 -6
  49. package/dist/lesson-pattern.js.map +1 -1
  50. package/dist/lesson-pattern.test.js +237 -1
  51. package/dist/lesson-pattern.test.js.map +1 -1
  52. package/dist/rule-engine.d.ts.map +1 -1
  53. package/dist/rule-engine.js +36 -10
  54. package/dist/rule-engine.js.map +1 -1
  55. package/dist/rule-engine.test.js +98 -4
  56. package/dist/rule-engine.test.js.map +1 -1
  57. package/dist/rule-tester.d.ts.map +1 -1
  58. package/dist/rule-tester.js +9 -2
  59. package/dist/rule-tester.js.map +1 -1
  60. package/dist/rule-tester.test.js +41 -0
  61. package/dist/rule-tester.test.js.map +1 -1
  62. package/dist/store/lance-store.d.ts +55 -1
  63. package/dist/store/lance-store.d.ts.map +1 -1
  64. package/dist/store/lance-store.js +140 -25
  65. package/dist/store/lance-store.js.map +1 -1
  66. package/dist/store/lance-store.test.js +77 -0
  67. package/dist/store/lance-store.test.js.map +1 -1
  68. package/dist/sys/git.d.ts +12 -1
  69. package/dist/sys/git.d.ts.map +1 -1
  70. package/dist/sys/git.js +59 -5
  71. package/dist/sys/git.js.map +1 -1
  72. package/dist/sys/git.test.js +23 -3
  73. package/dist/sys/git.test.js.map +1 -1
  74. package/package.json +1 -1
@@ -56,15 +56,119 @@ export function generateInputHash(lessonsDir) {
56
56
  }
57
57
  return hash.digest('hex');
58
58
  }
59
+ /**
60
+ * Deterministic JSON stringify. Walks the input tree and sorts every
61
+ * object's keys alphabetically before serialising. Arrays keep their
62
+ * element order (arrays are ordered by contract). Primitives and
63
+ * `null` pass through unchanged.
64
+ *
65
+ * Used by `generateOutputHash` so that a compound ast-grep rule
66
+ * (`astGrepYamlRule`) produces the same output hash regardless of the
67
+ * JS engine's property insertion order. Without this, two compile
68
+ * runs could emit functionally-identical rules with different key
69
+ * orders and trip `verify-manifest` on an otherwise stable lesson
70
+ * set. The invariant is: structurally-equivalent inputs produce
71
+ * byte-identical outputs.
72
+ *
73
+ * **Contract:** `value` MUST be plain JSON — the output of
74
+ * `JSON.parse()` or a literal composed of `null`, booleans, numbers,
75
+ * strings, arrays, and plain object literals. Class instances
76
+ * (`Date`, `Map`, custom classes) are not supported and may produce
77
+ * output that diverges from `JSON.stringify`: a `Date` serialises to
78
+ * `{}` rather than its ISO string, `[undefined]` throws rather than
79
+ * becoming `[null]`. Callers in Totem always pass `JSON.parse()`
80
+ * output, so these cases are unreachable in practice; the contract
81
+ * is documented here so future callers do not reach for this
82
+ * function as a drop-in `JSON.stringify` replacement.
83
+ *
84
+ * Design notes:
85
+ * - No cycle detection. Input is expected to be a finite tree
86
+ * (NapiConfig + primitive scalars). Cyclic input would stack
87
+ * overflow; that is a hard error, not a silent degradation.
88
+ * - Undefined values inside records are dropped, matching
89
+ * `JSON.stringify` parity. A bare `undefined` throws — it is
90
+ * not a JSON value.
91
+ */
92
+ /**
93
+ * Detect whether a parsed compiled-rules file contains at least one
94
+ * rule with an `astGrepYamlRule` field. Walks only the `rules` array
95
+ * on the top-level object; does not recurse into nested rule bodies
96
+ * because compound rules live exactly one level deep in the payload.
97
+ */
98
+ function hasCompoundRule(parsed) {
99
+ if (typeof parsed !== 'object' || parsed === null)
100
+ return false;
101
+ const rules = parsed.rules;
102
+ if (!Array.isArray(rules))
103
+ return false;
104
+ for (const r of rules) {
105
+ if (r && typeof r === 'object' && 'astGrepYamlRule' in r)
106
+ return true;
107
+ }
108
+ return false;
109
+ }
110
+ export function canonicalStringify(value) {
111
+ if (value === undefined) {
112
+ throw new TotemParseError('canonicalStringify: undefined is not a JSON value', 'The manifest hash payload must be JSON-parseable. Undefined entries are filtered out of records before serialisation, so a direct undefined here indicates a caller bug rather than malformed data on disk.');
113
+ }
114
+ if (value === null || typeof value !== 'object') {
115
+ return JSON.stringify(value);
116
+ }
117
+ if (Array.isArray(value)) {
118
+ return '[' + value.map((v) => canonicalStringify(v)).join(',') + ']';
119
+ }
120
+ const record = value;
121
+ const keys = Object.keys(record)
122
+ .filter((k) => record[k] !== undefined)
123
+ .sort();
124
+ const parts = [];
125
+ for (const k of keys) {
126
+ parts.push(JSON.stringify(k) + ':' + canonicalStringify(record[k]));
127
+ }
128
+ return '{' + parts.join(',') + '}';
129
+ }
59
130
  /**
60
131
  * Generate a deterministic SHA-256 hash of the compiled rules file.
61
132
  *
62
- * Line endings are normalized to `\n` before hashing.
133
+ * Line endings are normalized to `\n` before hashing. For files that
134
+ * contain at least one compound `astGrepYamlRule`, the payload is
135
+ * re-serialised through `canonicalStringify` so key-order variation
136
+ * inside the yaml object cannot shift the hash (mmnto/totem#1407).
137
+ * Files without any compound rule keep the byte-stream path for
138
+ * backward compatibility with manifests written by pre-#1407 CLIs:
139
+ * the old and new computation match byte-for-byte in that case, so
140
+ * every user's existing compile-manifest.json stays valid after
141
+ * upgrading without a forced recompile.
142
+ *
143
+ * A parse failure falls back to the raw content so verify-manifest
144
+ * can still catch tampering on partial writes; it does not mask the
145
+ * error.
63
146
  */
64
147
  export function generateOutputHash(rulesPath) {
65
148
  try {
66
- const content = fs.readFileSync(rulesPath, 'utf-8').replace(/\r\n/g, '\n');
67
- return crypto.createHash('sha256').update(content).digest('hex');
149
+ const raw = fs.readFileSync(rulesPath, 'utf-8').replace(/\r\n/g, '\n');
150
+ let payload = raw;
151
+ // Only switch to canonical serialization when the file actually
152
+ // contains a compound rule. We parse first and check the real
153
+ // field on every rule rather than substring-matching the raw
154
+ // bytes: a lesson message or heading could contain the literal
155
+ // string `"astGrepYamlRule"` and falsely flip the path,
156
+ // producing a different hash than pre-#1407 CLIs computed for
157
+ // the same manifest. Parsing is O(file size), same as hashing.
158
+ if (raw.includes('"astGrepYamlRule"')) {
159
+ try {
160
+ const parsed = JSON.parse(raw);
161
+ if (hasCompoundRule(parsed)) {
162
+ payload = canonicalStringify(parsed);
163
+ }
164
+ }
165
+ catch {
166
+ // Malformed JSON: keep the raw byte stream so verify-manifest
167
+ // still surfaces the corruption via a mismatch rather than
168
+ // crashing here.
169
+ }
170
+ }
171
+ return crypto.createHash('sha256').update(payload).digest('hex');
68
172
  }
69
173
  catch (err) {
70
174
  const code = err.code;
@@ -1 +1 @@
1
- {"version":3,"file":"compile-manifest.js","sourceRoot":"","sources":["../src/compile-manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,wDAAwD;AAExD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;CAC3C,CAAC,CAAC;AAIH,wDAAwD;AAExD;;;GAGG;AACH,SAAS,cAAc,CAAC,OAAe,EAAE,aAAqB,OAAO;IACnE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,eAAe,CACvB,gCAAgC,OAAO,EAAE,EACzC,+DAA+D,CAChE,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACnD,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;QACrD,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACxD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAkB;IAClD,MAAM,KAAK,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;IAChD,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAEzC,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE;iBACf,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC;iBACrD,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAC1B,IAAI,CAAC,MAAM,CAAC,GAAG,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC;QAC1C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,eAAe,CACvB,2BAA2B,OAAO,KAAK,eAAe,CAAC,GAAG,CAAC,EAAE,EAC7D,0DAA0D,EAC1D,GAAG,CACJ,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAiB;IAClD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC3E,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;QACjD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,MAAM,IAAI,eAAe,CACvB,+BAA+B,SAAS,YAAY,EACpD,sDAAsD,EACtD,GAAG,CACJ,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,eAAe,CACvB,+BAA+B,eAAe,CAAC,GAAG,CAAC,EAAE,EACrD,8BAA8B,SAAS,GAAG,EAC1C,GAAG,CACJ,CAAC;IACJ,CAAC;AACH,CAAC;AAED,wDAAwD;AAExD,MAAM,SAAS,GAAG,KAAK,CAAC;AAExB;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,YAAoB,EAAE,QAAyB;IAClF,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;IACtD,IAAI,CAAC;QACH,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IAC/E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,eAAe,CACvB,kCAAkC,eAAe,CAAC,GAAG,CAAC,EAAE,EACxD,+BAA+B,YAAY,GAAG,EAC9C,GAAG,CACJ,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,YAAoB;IACtD,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,YAAY,EAAE,qBAAqB,CAAC,CAAC;IAC3D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,CAAC,GAAG,YAAY,eAAe,CAAC;YAAE,MAAM,GAAG,CAAC;QACjD,iDAAiD;QACjD,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC3C,MAAM,IAAI,eAAe,CACvB,+BAA+B,YAAY,EAAE,EAC7C,+CAA+C,EAC/C,GAAG,CAAC,KAAK,CACV,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,eAAe,CACvB,qCAAqC,YAAY,EAAE,EACnD,yDAAyD,EACzD,GAAG,CAAC,KAAK,CACV,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,eAAe,CACvB,oCAAoC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAC/E,wEAAwE,EACxE,GAAG,CAAC,KAAK,CACV,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"compile-manifest.js","sourceRoot":"","sources":["../src/compile-manifest.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,9 @@
1
+ import * as crypto from 'node:crypto';
1
2
  import * as fs from 'node:fs';
2
3
  import * as os from 'node:os';
3
4
  import * as path from 'node:path';
4
5
  import { afterEach, beforeEach, describe, expect, it } from 'vitest';
5
- import { generateInputHash, generateOutputHash, readCompileManifest, writeCompileManifest, } from './compile-manifest.js';
6
+ import { canonicalStringify, generateInputHash, generateOutputHash, readCompileManifest, writeCompileManifest, } from './compile-manifest.js';
6
7
  import { TotemParseError } from './errors.js';
7
8
  import { cleanTmpDir } from './test-utils.js';
8
9
  describe('generateInputHash', () => {
@@ -51,6 +52,127 @@ describe('generateOutputHash', () => {
51
52
  fs.writeFileSync(pathCRLF, '{"rules": []}\r\n');
52
53
  expect(generateOutputHash(pathLF)).toBe(generateOutputHash(pathCRLF));
53
54
  });
55
+ it('manifest hash generates identical hashes for astGrepYamlRule objects with differently ordered keys', () => {
56
+ const pathA = path.join(tmpDir, 'rules-a.json');
57
+ const pathB = path.join(tmpDir, 'rules-b.json');
58
+ const ruleA = {
59
+ lessonHash: 'abc',
60
+ lessonHeading: 'Test',
61
+ pattern: '',
62
+ message: 'm',
63
+ engine: 'ast-grep',
64
+ compiledAt: '2026-04-13T00:00:00Z',
65
+ astGrepYamlRule: {
66
+ rule: {
67
+ all: [{ pattern: 'foo($A)' }, { inside: { kind: 'function_declaration' } }],
68
+ },
69
+ },
70
+ };
71
+ // Same semantic rule, scrambled keys at every level.
72
+ const ruleB = {
73
+ engine: 'ast-grep',
74
+ astGrepYamlRule: {
75
+ rule: {
76
+ all: [{ pattern: 'foo($A)' }, { inside: { kind: 'function_declaration' } }],
77
+ },
78
+ },
79
+ pattern: '',
80
+ compiledAt: '2026-04-13T00:00:00Z',
81
+ lessonHash: 'abc',
82
+ message: 'm',
83
+ lessonHeading: 'Test',
84
+ };
85
+ fs.writeFileSync(pathA, JSON.stringify({ version: 1, rules: [ruleA] }, null, 2) + '\n');
86
+ fs.writeFileSync(pathB, JSON.stringify({ version: 1, rules: [ruleB] }, null, 2) + '\n');
87
+ expect(generateOutputHash(pathA)).toBe(generateOutputHash(pathB));
88
+ });
89
+ it('does not switch to canonical path when the literal string appears only in a lesson message', () => {
90
+ // Regression for the substring false-positive flagged on #1412:
91
+ // a rule whose message body contains the bytes `"astGrepYamlRule"`
92
+ // (e.g., a lesson about when to use the new field) must NOT flip
93
+ // the hash computation path. Pre-#1407 CLIs would hash the raw
94
+ // byte stream; a false canonical path produces different bytes.
95
+ const pathByteStream = path.join(tmpDir, 'rules-bytes.json');
96
+ const pathWithStringInMessage = path.join(tmpDir, 'rules-msg.json');
97
+ const plainRule = {
98
+ lessonHash: 'plain',
99
+ lessonHeading: 'regex rule',
100
+ pattern: 'foo',
101
+ message: 'use foo instead of bar',
102
+ engine: 'regex',
103
+ compiledAt: '2026-04-13T00:00:00Z',
104
+ };
105
+ const trickyRule = {
106
+ lessonHash: 'tricky',
107
+ lessonHeading: 'mention the field',
108
+ pattern: 'foo',
109
+ // Literal bytes `"astGrepYamlRule"` inside a message (wrapping
110
+ // the name in single quotes in prose would still JSON-encode to
111
+ // a version that does NOT contain the double-quoted token —
112
+ // this test uses the token explicitly to force the worst case).
113
+ message: 'prefer astGrepPattern over "astGrepYamlRule" for flat patterns',
114
+ engine: 'regex',
115
+ compiledAt: '2026-04-13T00:00:00Z',
116
+ };
117
+ const plainJson = JSON.stringify({ version: 1, rules: [plainRule] }, null, 2) + '\n';
118
+ const trickyJson = JSON.stringify({ version: 1, rules: [trickyRule] }, null, 2) + '\n';
119
+ fs.writeFileSync(pathByteStream, plainJson);
120
+ fs.writeFileSync(pathWithStringInMessage, trickyJson);
121
+ // Hashes differ (different messages), but the tricky rule must
122
+ // have been hashed via the raw-byte-stream path, not canonical.
123
+ // Proof: the canonical path on tricky would produce a different
124
+ // hash than crypto over the raw bytes. Compare against the raw
125
+ // sha256 of the file contents.
126
+ const expectedTrickyHash = crypto
127
+ .createHash('sha256')
128
+ .update(trickyJson.replace(/\r\n/g, '\n'))
129
+ .digest('hex');
130
+ expect(generateOutputHash(pathWithStringInMessage)).toBe(expectedTrickyHash);
131
+ });
132
+ });
133
+ describe('canonicalStringify', () => {
134
+ it('sorts top-level object keys', () => {
135
+ expect(canonicalStringify({ b: 2, a: 1 })).toBe(canonicalStringify({ a: 1, b: 2 }));
136
+ });
137
+ it('sorts keys at every nesting depth', () => {
138
+ const a = { z: { y: { x: 1, w: 2 } }, a: 0 };
139
+ const b = { a: 0, z: { y: { w: 2, x: 1 } } };
140
+ expect(canonicalStringify(a)).toBe(canonicalStringify(b));
141
+ });
142
+ it('preserves array element order (arrays are ordered by contract)', () => {
143
+ expect(canonicalStringify([2, 1, 3])).not.toBe(canonicalStringify([1, 2, 3]));
144
+ });
145
+ it('handles nested arrays of objects with scrambled keys', () => {
146
+ const a = {
147
+ rule: {
148
+ all: [{ pattern: 'foo', kind: 'call' }, { inside: { stopBy: 'end', kind: 'function' } }],
149
+ },
150
+ };
151
+ const b = {
152
+ rule: {
153
+ all: [{ kind: 'call', pattern: 'foo' }, { inside: { kind: 'function', stopBy: 'end' } }],
154
+ },
155
+ };
156
+ expect(canonicalStringify(a)).toBe(canonicalStringify(b));
157
+ });
158
+ it('is stable for primitives', () => {
159
+ expect(canonicalStringify('hello')).toBe('"hello"');
160
+ expect(canonicalStringify(42)).toBe('42');
161
+ expect(canonicalStringify(true)).toBe('true');
162
+ expect(canonicalStringify(null)).toBe('null');
163
+ });
164
+ it('handles undefined by omitting the key (JSON.stringify parity)', () => {
165
+ const a = { a: 1, b: undefined };
166
+ const b = { a: 1 };
167
+ expect(canonicalStringify(a)).toBe(canonicalStringify(b));
168
+ });
169
+ it('throws on a bare undefined input (contract violation)', () => {
170
+ // Undefined in record values is filtered out upstream; a bare
171
+ // undefined here means a caller bug, not malformed data on disk.
172
+ // Fail loud rather than silently produce the string "undefined"
173
+ // that would then hash to something no other input produces.
174
+ expect(() => canonicalStringify(undefined)).toThrow(/undefined is not a JSON value/);
175
+ });
54
176
  });
55
177
  describe('writeCompileManifest + readCompileManifest', () => {
56
178
  let tmpDir;
@@ -1 +1 @@
1
- {"version":3,"file":"compile-manifest.test.js","sourceRoot":"","sources":["../src/compile-manifest.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compile-manifest.test.js","sourceRoot":"","sources":["../src/compile-manifest.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Compile-time smoke gate for compiled rules (ADR-087).
3
+ *
4
+ * Runs a freshly built `CompiledRule` against its own `badExample` snippet
5
+ * using the same engine entry points that the runtime uses (`matchAstGrepPattern`
6
+ * for ast-grep, `new RegExp` for regex). If the rule cannot match its own
7
+ * bad example, something structurally wrong happened between the LLM output
8
+ * and the persisted rule shape — either the pattern does not compile against
9
+ * the snippet, or the snippet does not exercise the pattern the prompt
10
+ * promised. Either way, the rule has no business in compiled-rules.json.
11
+ *
12
+ * The gate is intentionally a thin wrapper: its entire purpose is to
13
+ * guarantee that a rule passing here will also fire at runtime on identical
14
+ * input. Any divergence between "smoke gate happy" and "runtime happy" is a
15
+ * bug in this module, not a rule authoring problem.
16
+ *
17
+ * Not wired to Pipeline 1 (manual) rules in mmnto/totem#1408 - a dry-run
18
+ * sweep lands in a follow-up ticket before the Pipeline 1 gate flips on.
19
+ */
20
+ import type { CompiledRule } from './compiler-schema.js';
21
+ export interface SmokeGateResult {
22
+ /** True when the rule produced at least one match against the badExample. */
23
+ matched: boolean;
24
+ /** Number of matches the engine reported. Zero when `matched` is false. */
25
+ matchCount: number;
26
+ /**
27
+ * When matched is false and the engine refused to execute (invalid regex,
28
+ * ast-grep runtime throw, missing engine fields), this carries the first
29
+ * line of the error so the caller can build a human-readable rejectReason.
30
+ * Absent when matched is true, and absent when matched is false due to the
31
+ * snippet simply not containing anything the pattern would match.
32
+ */
33
+ reason?: string;
34
+ }
35
+ /**
36
+ * Run the smoke gate for a compiled rule. Returns a `SmokeGateResult` so the
37
+ * caller can decide whether to accept or reject the rule. The caller is
38
+ * responsible for the "zero matches means reject" decision; this function
39
+ * only reports what the engine says.
40
+ */
41
+ export declare function runSmokeGate(rule: CompiledRule, badExample: string): SmokeGateResult;
42
+ //# sourceMappingURL=compile-smoke-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile-smoke-gate.d.ts","sourceRoot":"","sources":["../src/compile-smoke-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAIzD,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,OAAO,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA2FD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,eAAe,CA8BpF"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Compile-time smoke gate for compiled rules (ADR-087).
3
+ *
4
+ * Runs a freshly built `CompiledRule` against its own `badExample` snippet
5
+ * using the same engine entry points that the runtime uses (`matchAstGrepPattern`
6
+ * for ast-grep, `new RegExp` for regex). If the rule cannot match its own
7
+ * bad example, something structurally wrong happened between the LLM output
8
+ * and the persisted rule shape — either the pattern does not compile against
9
+ * the snippet, or the snippet does not exercise the pattern the prompt
10
+ * promised. Either way, the rule has no business in compiled-rules.json.
11
+ *
12
+ * The gate is intentionally a thin wrapper: its entire purpose is to
13
+ * guarantee that a rule passing here will also fire at runtime on identical
14
+ * input. Any divergence between "smoke gate happy" and "runtime happy" is a
15
+ * bug in this module, not a rule authoring problem.
16
+ *
17
+ * Not wired to Pipeline 1 (manual) rules in mmnto/totem#1408 - a dry-run
18
+ * sweep lands in a follow-up ticket before the Pipeline 1 gate flips on.
19
+ */
20
+ import { matchAstGrepPattern } from './ast-grep-query.js';
21
+ // ─── Helpers ────────────────────────────────────────
22
+ function firstLine(message) {
23
+ const m = /^[^\n]*/.exec(message);
24
+ return (m?.[0] ?? message).trim();
25
+ }
26
+ function lineNumbersFor(snippet) {
27
+ const lineCount = snippet.split('\n').length;
28
+ const result = [];
29
+ for (let i = 1; i <= lineCount; i++)
30
+ result.push(i);
31
+ return result;
32
+ }
33
+ // ─── Engine runners ─────────────────────────────────
34
+ function runRegexGate(pattern, badExample) {
35
+ let re;
36
+ try {
37
+ re = new RegExp(pattern);
38
+ }
39
+ catch (err) {
40
+ return {
41
+ matched: false,
42
+ matchCount: 0,
43
+ reason: `invalid regex: ${firstLine(err instanceof Error ? err.message : String(err))}`,
44
+ };
45
+ }
46
+ let matchCount = 0;
47
+ for (const line of badExample.split('\n')) {
48
+ if (re.test(line))
49
+ matchCount++;
50
+ }
51
+ return matchCount > 0 ? { matched: true, matchCount } : { matched: false, matchCount: 0 };
52
+ }
53
+ /**
54
+ * Collect the ordered list of file extensions the ast-grep engine could use
55
+ * when parsing the badExample. Returns every positive match from
56
+ * `fileGlobs`; if no globs are declared, returns a broad default set so an
57
+ * unscoped rule still has a chance to match the snippet under some parser.
58
+ *
59
+ * Why a list rather than a single extension: `.ts` and `.tsx` select
60
+ * different tree-sitter parsers that reject each other's syntax. A TS
61
+ * angle-bracket cast (`const x = <Foo>bar;`) parses as TS but not as TSX;
62
+ * a JSX element parses as TSX but not as TS. If the rule's fileGlobs
63
+ * allow multiple extensions, runtime will pick whichever matches the real
64
+ * file, so the gate must try every declared extension too. Passing on ANY
65
+ * extension is sufficient — runtime scans the same surface.
66
+ */
67
+ function inferBadExampleExts(rule) {
68
+ const exts = new Set();
69
+ for (const g of rule.fileGlobs ?? []) {
70
+ if (g.startsWith('!'))
71
+ continue;
72
+ for (const m of g.matchAll(/\.(ts|tsx|js|jsx|mjs|cjs)\b/gi)) {
73
+ exts.add(`.${m[1].toLowerCase()}`);
74
+ }
75
+ }
76
+ // Unscoped rule: try the full supported set so the gate does not
77
+ // false-reject on a snippet that would match under some parser. Order
78
+ // puts TypeScript first (handles cast syntax), then TSX, then JS
79
+ // variants. Parity with runtime is preserved because runtime also
80
+ // executes the rule against any file whose extension matches.
81
+ return exts.size > 0 ? [...exts] : ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
82
+ }
83
+ function runAstGrepGate(pattern, badExample, rule) {
84
+ const lineNumbers = lineNumbersFor(badExample);
85
+ let lastReason;
86
+ for (const ext of inferBadExampleExts(rule)) {
87
+ try {
88
+ const matches = matchAstGrepPattern(badExample, ext, pattern, lineNumbers);
89
+ if (matches.length > 0) {
90
+ return { matched: true, matchCount: matches.length };
91
+ }
92
+ }
93
+ catch (err) {
94
+ lastReason = `ast-grep runtime error: ${firstLine(err instanceof Error ? err.message : String(err))}`;
95
+ }
96
+ }
97
+ return lastReason
98
+ ? { matched: false, matchCount: 0, reason: lastReason }
99
+ : { matched: false, matchCount: 0 };
100
+ }
101
+ // ─── Public API ─────────────────────────────────────
102
+ /**
103
+ * Run the smoke gate for a compiled rule. Returns a `SmokeGateResult` so the
104
+ * caller can decide whether to accept or reject the rule. The caller is
105
+ * responsible for the "zero matches means reject" decision; this function
106
+ * only reports what the engine says.
107
+ */
108
+ export function runSmokeGate(rule, badExample) {
109
+ if (!badExample || badExample.trim().length === 0) {
110
+ return { matched: false, matchCount: 0 };
111
+ }
112
+ if (rule.engine === 'regex') {
113
+ return runRegexGate(rule.pattern, badExample);
114
+ }
115
+ if (rule.engine === 'ast-grep') {
116
+ const source = rule.astGrepPattern ?? rule.astGrepYamlRule;
117
+ if (!source) {
118
+ return {
119
+ matched: false,
120
+ matchCount: 0,
121
+ reason: 'ast-grep rule missing both astGrepPattern and astGrepYamlRule',
122
+ };
123
+ }
124
+ return runAstGrepGate(source, badExample, rule);
125
+ }
126
+ // Tree-sitter ast engine: not wired into the gate in mmnto/totem#1408.
127
+ // Callers should not pass 'ast' rules; surface a neutral skip so the
128
+ // caller can fall back to legacy verification.
129
+ return {
130
+ matched: false,
131
+ matchCount: 0,
132
+ reason: `smoke gate does not yet cover engine: ${rule.engine}`,
133
+ };
134
+ }
135
+ //# sourceMappingURL=compile-smoke-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile-smoke-gate.js","sourceRoot":"","sources":["../src/compile-smoke-gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=compile-smoke-gate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile-smoke-gate.test.d.ts","sourceRoot":"","sources":["../src/compile-smoke-gate.test.ts"],"names":[],"mappings":""}