@mmnto/totem 1.77.0 → 1.79.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 (66) hide show
  1. package/dist/artifacts/panel.d.ts +48 -48
  2. package/dist/artifacts/schema.d.ts +40 -40
  3. package/dist/compiler-schema.d.ts +1048 -7
  4. package/dist/compiler-schema.d.ts.map +1 -1
  5. package/dist/compiler-schema.js +129 -1
  6. package/dist/compiler-schema.js.map +1 -1
  7. package/dist/compiler-schema.test.js +92 -2
  8. package/dist/compiler-schema.test.js.map +1 -1
  9. package/dist/compiler.d.ts +2 -2
  10. package/dist/compiler.d.ts.map +1 -1
  11. package/dist/compiler.js +1 -1
  12. package/dist/compiler.js.map +1 -1
  13. package/dist/index.d.ts +10 -6
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +4 -2
  16. package/dist/index.js.map +1 -1
  17. package/dist/parity-detect.d.ts +127 -0
  18. package/dist/parity-detect.d.ts.map +1 -1
  19. package/dist/parity-detect.js +425 -1
  20. package/dist/parity-detect.js.map +1 -1
  21. package/dist/parity-lock-content.test.d.ts +9 -0
  22. package/dist/parity-lock-content.test.d.ts.map +1 -0
  23. package/dist/parity-lock-content.test.js +432 -0
  24. package/dist/parity-lock-content.test.js.map +1 -0
  25. package/dist/parity-manifest.d.ts +1 -1
  26. package/dist/parity-manifest.d.ts.map +1 -1
  27. package/dist/parity-manifest.js +6 -0
  28. package/dist/parity-manifest.js.map +1 -1
  29. package/dist/spine/authored-rule.d.ts +360 -0
  30. package/dist/spine/authored-rule.d.ts.map +1 -0
  31. package/dist/spine/authored-rule.js +199 -0
  32. package/dist/spine/authored-rule.js.map +1 -0
  33. package/dist/spine/authored-rule.test.d.ts +2 -0
  34. package/dist/spine/authored-rule.test.d.ts.map +1 -0
  35. package/dist/spine/authored-rule.test.js +220 -0
  36. package/dist/spine/authored-rule.test.js.map +1 -0
  37. package/dist/spine/candidate-rule.d.ts +32 -0
  38. package/dist/spine/candidate-rule.d.ts.map +1 -1
  39. package/dist/spine/candidate-rule.js +2 -2
  40. package/dist/spine/candidate-rule.js.map +1 -1
  41. package/dist/spine/classify.d.ts +5 -5
  42. package/dist/spine/compile.d.ts +16 -4
  43. package/dist/spine/compile.d.ts.map +1 -1
  44. package/dist/spine/compile.js +23 -0
  45. package/dist/spine/compile.js.map +1 -1
  46. package/dist/spine/compile.test.js +69 -0
  47. package/dist/spine/compile.test.js.map +1 -1
  48. package/dist/spine/corpus-dispositions.d.ts +18 -18
  49. package/dist/spine/extract.d.ts +2 -2
  50. package/dist/spine/extract.d.ts.map +1 -1
  51. package/dist/spine/extract.js +5 -4
  52. package/dist/spine/extract.js.map +1 -1
  53. package/dist/spine/ledgers.d.ts +46 -21
  54. package/dist/spine/ledgers.d.ts.map +1 -1
  55. package/dist/spine/ledgers.js +16 -8
  56. package/dist/spine/ledgers.js.map +1 -1
  57. package/dist/spine/rule-policy.d.ts +27 -0
  58. package/dist/spine/rule-policy.d.ts.map +1 -0
  59. package/dist/spine/rule-policy.js +43 -0
  60. package/dist/spine/rule-policy.js.map +1 -0
  61. package/dist/spine/rule-policy.test.d.ts +2 -0
  62. package/dist/spine/rule-policy.test.d.ts.map +1 -0
  63. package/dist/spine/rule-policy.test.js +31 -0
  64. package/dist/spine/rule-policy.test.js.map +1 -0
  65. package/dist/spine/windtunnel-lock.d.ts +8 -8
  66. package/package.json +1 -1
@@ -0,0 +1,360 @@
1
+ import { z } from 'zod';
2
+ import type { CompileInputCandidate } from './candidate-rule.js';
3
+ import type { ClassifierLedger } from './ledgers.js';
4
+ /** The matcher engines an authored rule may declare (mirrors `CompiledRule.engine`). */
5
+ export declare const DeclaredEngineSchema: z.ZodEnum<["regex", "ast", "ast-grep"]>;
6
+ export type DeclaredEngine = z.infer<typeof DeclaredEngineSchema>;
7
+ /**
8
+ * ADR-112 §3 — the result of the INDEPENDENT structural-eligibility check.
9
+ * Produced by `evaluateStructuralEligibility` (NOT by the author): only
10
+ * `decidable: true` reaches the compiler, mapping to the compiler's
11
+ * `classifierDisposition: 'structural'`. `judgedBy` records who/what judged it
12
+ * (ledger-recorded, never the author), so a human cannot smuggle a behavioral
13
+ * policy past ADR-091's gate by hand-asserting "structural" (FM(d)).
14
+ */
15
+ export declare const StructEligResultSchema: z.ZodObject<{
16
+ decidable: z.ZodBoolean;
17
+ /**
18
+ * `whitelist:<class>` for the cert-#1 static-whitelist basis; the
19
+ * `capability-check` / `draft-classifier+stage4` bases are contract-legal but
20
+ * deferred (slice-A uses the deterministic whitelist only). On a `decidable:
21
+ * false` verdict the basis still names the attempted whitelist class — the
22
+ * diagnostic is "no/ambiguous whitelist match", carried in `judgedBy`'s log.
23
+ * Constrained to the §3 forms (strategy item 2, #2259) so a typo'd/free-form
24
+ * basis can't validate — non-mutating (no `.trim()`), matching the hash-stability
25
+ * discipline on the other reference fields.
26
+ */
27
+ basis: z.ZodEffects<z.ZodString, string, string>;
28
+ judgedBy: z.ZodEffects<z.ZodString, string, string>;
29
+ }, "strip", z.ZodTypeAny, {
30
+ decidable: boolean;
31
+ basis: string;
32
+ judgedBy: string;
33
+ }, {
34
+ decidable: boolean;
35
+ basis: string;
36
+ judgedBy: string;
37
+ }>;
38
+ export type StructEligResult = z.infer<typeof StructEligResultSchema>;
39
+ /** ADR-112 §3/§7 — accelerant-lineage marker. A mined hint that informed a human is recorded, never erased. */
40
+ export declare const AuthoredOriginSchema: z.ZodUnion<[z.ZodObject<{
41
+ kind: z.ZodLiteral<"from-scratch">;
42
+ }, "strip", z.ZodTypeAny, {
43
+ kind: "from-scratch";
44
+ }, {
45
+ kind: "from-scratch";
46
+ }>, z.ZodObject<{
47
+ kind: z.ZodLiteral<"mined-accelerant">;
48
+ sourceRunId: z.ZodEffects<z.ZodString, string, string>;
49
+ suggestionHash: z.ZodEffects<z.ZodString, string, string>;
50
+ }, "strip", z.ZodTypeAny, {
51
+ kind: "mined-accelerant";
52
+ sourceRunId: string;
53
+ suggestionHash: string;
54
+ }, {
55
+ kind: "mined-accelerant";
56
+ sourceRunId: string;
57
+ suggestionHash: string;
58
+ }>]>;
59
+ export type AuthoredOrigin = z.infer<typeof AuthoredOriginSchema>;
60
+ /**
61
+ * ADR-112 §3 — the authored producer's sole output envelope. Parallel to
62
+ * ADR-111's `CandidateRuleRecord` but carrying the AUTHORED provenance variant,
63
+ * the INDEPENDENTLY-judged eligibility result, and the accelerant lineage.
64
+ * Minted `unverified: true` (ADR-089) — zero enforcement blast radius.
65
+ */
66
+ export declare const AuthoredRuleRecordSchema: z.ZodObject<{
67
+ /**
68
+ * ADR-112 §3/§8 — the stable, minted rule identity (`mintAuthoredRuleId`),
69
+ * assigned ONCE at authoring time and PERSISTED on the record; NEVER re-derived
70
+ * from content at read time. `firingLabelId` + the §5.3
71
+ * `controls.positive[].targetRuleId` ground-truth labels embed it, so a
72
+ * content-re-derived id would orphan them (§8). Slice A reserves the field (this
73
+ * IS the schema spine); the authoring flow (slice B) mints it, and threading it
74
+ * into the compiled artifact's identity (`firingLabelId ← ruleId`, replacing the
75
+ * `dslSource`-derived `lessonHash`) is slice C/D. The RESOLVED id (with any `-N`
76
+ * collision suffix) is what is stored.
77
+ */
78
+ ruleId: z.ZodString;
79
+ provenance: z.ZodObject<{
80
+ kind: z.ZodLiteral<"authored">;
81
+ author: z.ZodEffects<z.ZodString, string, string>;
82
+ authoredAt: z.ZodEffects<z.ZodString, string, string>;
83
+ targetDefect: z.ZodEffects<z.ZodString, string, string>;
84
+ positiveFixtures: z.ZodArray<z.ZodObject<{
85
+ pr: z.ZodNumber;
86
+ mergeCommitSha: z.ZodString;
87
+ preimageCommitSha: z.ZodString;
88
+ filePath: z.ZodEffects<z.ZodString, string, string>;
89
+ matchedSpan: z.ZodEffects<z.ZodString, string, string>;
90
+ contentHash: z.ZodEffects<z.ZodString, string, string>;
91
+ }, "strip", z.ZodTypeAny, {
92
+ pr: number;
93
+ mergeCommitSha: string;
94
+ preimageCommitSha: string;
95
+ filePath: string;
96
+ matchedSpan: string;
97
+ contentHash: string;
98
+ }, {
99
+ pr: number;
100
+ mergeCommitSha: string;
101
+ preimageCommitSha: string;
102
+ filePath: string;
103
+ matchedSpan: string;
104
+ contentHash: string;
105
+ }>, "many">;
106
+ negativeFixtures: z.ZodOptional<z.ZodArray<z.ZodObject<{
107
+ pr: z.ZodNumber;
108
+ mergeCommitSha: z.ZodString;
109
+ preimageCommitSha: z.ZodString;
110
+ filePath: z.ZodEffects<z.ZodString, string, string>;
111
+ matchedSpan: z.ZodEffects<z.ZodString, string, string>;
112
+ contentHash: z.ZodEffects<z.ZodString, string, string>;
113
+ }, "strip", z.ZodTypeAny, {
114
+ pr: number;
115
+ mergeCommitSha: string;
116
+ preimageCommitSha: string;
117
+ filePath: string;
118
+ matchedSpan: string;
119
+ contentHash: string;
120
+ }, {
121
+ pr: number;
122
+ mergeCommitSha: string;
123
+ preimageCommitSha: string;
124
+ filePath: string;
125
+ matchedSpan: string;
126
+ contentHash: string;
127
+ }>, "many">>;
128
+ }, "strip", z.ZodTypeAny, {
129
+ kind: "authored";
130
+ author: string;
131
+ authoredAt: string;
132
+ targetDefect: string;
133
+ positiveFixtures: {
134
+ pr: number;
135
+ mergeCommitSha: string;
136
+ preimageCommitSha: string;
137
+ filePath: string;
138
+ matchedSpan: string;
139
+ contentHash: string;
140
+ }[];
141
+ negativeFixtures?: {
142
+ pr: number;
143
+ mergeCommitSha: string;
144
+ preimageCommitSha: string;
145
+ filePath: string;
146
+ matchedSpan: string;
147
+ contentHash: string;
148
+ }[] | undefined;
149
+ }, {
150
+ kind: "authored";
151
+ author: string;
152
+ authoredAt: string;
153
+ targetDefect: string;
154
+ positiveFixtures: {
155
+ pr: number;
156
+ mergeCommitSha: string;
157
+ preimageCommitSha: string;
158
+ filePath: string;
159
+ matchedSpan: string;
160
+ contentHash: string;
161
+ }[];
162
+ negativeFixtures?: {
163
+ pr: number;
164
+ mergeCommitSha: string;
165
+ preimageCommitSha: string;
166
+ filePath: string;
167
+ matchedSpan: string;
168
+ contentHash: string;
169
+ }[] | undefined;
170
+ }>;
171
+ /** INDEPENDENTLY established (§3) — the author never sets this; the check does. */
172
+ structuralEligibility: z.ZodObject<{
173
+ decidable: z.ZodBoolean;
174
+ /**
175
+ * `whitelist:<class>` for the cert-#1 static-whitelist basis; the
176
+ * `capability-check` / `draft-classifier+stage4` bases are contract-legal but
177
+ * deferred (slice-A uses the deterministic whitelist only). On a `decidable:
178
+ * false` verdict the basis still names the attempted whitelist class — the
179
+ * diagnostic is "no/ambiguous whitelist match", carried in `judgedBy`'s log.
180
+ * Constrained to the §3 forms (strategy item 2, #2259) so a typo'd/free-form
181
+ * basis can't validate — non-mutating (no `.trim()`), matching the hash-stability
182
+ * discipline on the other reference fields.
183
+ */
184
+ basis: z.ZodEffects<z.ZodString, string, string>;
185
+ judgedBy: z.ZodEffects<z.ZodString, string, string>;
186
+ }, "strip", z.ZodTypeAny, {
187
+ decidable: boolean;
188
+ basis: string;
189
+ judgedBy: string;
190
+ }, {
191
+ decidable: boolean;
192
+ basis: string;
193
+ judgedBy: string;
194
+ }>;
195
+ origin: z.ZodUnion<[z.ZodObject<{
196
+ kind: z.ZodLiteral<"from-scratch">;
197
+ }, "strip", z.ZodTypeAny, {
198
+ kind: "from-scratch";
199
+ }, {
200
+ kind: "from-scratch";
201
+ }>, z.ZodObject<{
202
+ kind: z.ZodLiteral<"mined-accelerant">;
203
+ sourceRunId: z.ZodEffects<z.ZodString, string, string>;
204
+ suggestionHash: z.ZodEffects<z.ZodString, string, string>;
205
+ }, "strip", z.ZodTypeAny, {
206
+ kind: "mined-accelerant";
207
+ sourceRunId: string;
208
+ suggestionHash: string;
209
+ }, {
210
+ kind: "mined-accelerant";
211
+ sourceRunId: string;
212
+ suggestionHash: string;
213
+ }>]>;
214
+ declaredEngine: z.ZodEnum<["regex", "ast", "ast-grep"]>;
215
+ /** Reference to the §8 authoring-ledger entry (author/date/engine/splitRef/attestations). */
216
+ authoringLedgerRef: z.ZodEffects<z.ZodString, string, string>;
217
+ /** The human-written matcher (same DSL the compiler accepts from the miner). */
218
+ dslSource: z.ZodEffects<z.ZodString, string, string>;
219
+ /** Zero-trust mint (ADR-089 / ADR-112 §1) — always literally `true`. */
220
+ unverified: z.ZodLiteral<true>;
221
+ }, "strip", z.ZodTypeAny, {
222
+ provenance: {
223
+ kind: "authored";
224
+ author: string;
225
+ authoredAt: string;
226
+ targetDefect: string;
227
+ positiveFixtures: {
228
+ pr: number;
229
+ mergeCommitSha: string;
230
+ preimageCommitSha: string;
231
+ filePath: string;
232
+ matchedSpan: string;
233
+ contentHash: string;
234
+ }[];
235
+ negativeFixtures?: {
236
+ pr: number;
237
+ mergeCommitSha: string;
238
+ preimageCommitSha: string;
239
+ filePath: string;
240
+ matchedSpan: string;
241
+ contentHash: string;
242
+ }[] | undefined;
243
+ };
244
+ unverified: true;
245
+ ruleId: string;
246
+ origin: {
247
+ kind: "from-scratch";
248
+ } | {
249
+ kind: "mined-accelerant";
250
+ sourceRunId: string;
251
+ suggestionHash: string;
252
+ };
253
+ dslSource: string;
254
+ structuralEligibility: {
255
+ decidable: boolean;
256
+ basis: string;
257
+ judgedBy: string;
258
+ };
259
+ declaredEngine: "regex" | "ast" | "ast-grep";
260
+ authoringLedgerRef: string;
261
+ }, {
262
+ provenance: {
263
+ kind: "authored";
264
+ author: string;
265
+ authoredAt: string;
266
+ targetDefect: string;
267
+ positiveFixtures: {
268
+ pr: number;
269
+ mergeCommitSha: string;
270
+ preimageCommitSha: string;
271
+ filePath: string;
272
+ matchedSpan: string;
273
+ contentHash: string;
274
+ }[];
275
+ negativeFixtures?: {
276
+ pr: number;
277
+ mergeCommitSha: string;
278
+ preimageCommitSha: string;
279
+ filePath: string;
280
+ matchedSpan: string;
281
+ contentHash: string;
282
+ }[] | undefined;
283
+ };
284
+ unverified: true;
285
+ ruleId: string;
286
+ origin: {
287
+ kind: "from-scratch";
288
+ } | {
289
+ kind: "mined-accelerant";
290
+ sourceRunId: string;
291
+ suggestionHash: string;
292
+ };
293
+ dslSource: string;
294
+ structuralEligibility: {
295
+ decidable: boolean;
296
+ basis: string;
297
+ judgedBy: string;
298
+ };
299
+ declaredEngine: "regex" | "ast" | "ast-grep";
300
+ authoringLedgerRef: string;
301
+ }>;
302
+ export type AuthoredRuleRecord = z.infer<typeof AuthoredRuleRecordSchema>;
303
+ /**
304
+ * One decidable `(engine, structuralClass)` pair. The whitelist of these lives
305
+ * in the CLI registry (slice B); the registry lists ONLY pairs the engine can
306
+ * actually represent, so "exactly one match" subsumes ADR-112 §3's "AND the
307
+ * engine can represent that class" condition.
308
+ */
309
+ export interface WhitelistEntry {
310
+ engine: DeclaredEngine;
311
+ structuralClass: string;
312
+ }
313
+ /**
314
+ * ADR-112 §3 — the INDEPENDENT structural-eligibility check. A CLOSED registry
315
+ * predicate, NOT prose: `decidable` is true iff EXACTLY ONE whitelist entry
316
+ * matches `(declaredEngine, structuralClass)`. Unknown class, unsupported
317
+ * engine, or multiple matches → `decidable: false` (NO default-to-structural).
318
+ * The author supplies `declaredEngine` + `structuralClass`; this check OWNS the
319
+ * verdict — any author-supplied disposition is irrelevant here (FM(d)).
320
+ * Deterministic + pure (no IO, no LLM) — the same input always yields the same
321
+ * verdict (Tenet-15).
322
+ */
323
+ export declare function evaluateStructuralEligibility(input: {
324
+ declaredEngine: DeclaredEngine;
325
+ structuralClass: string;
326
+ }, whitelist: readonly WhitelistEntry[], judgedBy: string): StructEligResult;
327
+ /**
328
+ * ADR-112 §8 — mint a stable, deterministic authored rule-id. The seed is
329
+ * `sha256(JSON.stringify([author, targetDefect]))[:16]` (an INJECTIVE encoding —
330
+ * see the inline note) — `dslSource` is DELIBERATELY EXCLUDED so an author can
331
+ * tighten/refactor the matcher without orphaning the rule's ledger history. On collision with an already-resolved id (two rules sharing the same
332
+ * `(author, targetDefect)`), a stable `-N` counter is appended. The RESOLVED id
333
+ * is what callers persist — never recompute the raw seed at read time, or a
334
+ * later sibling could shift the suffix (the gemini/agy break). The
335
+ * `never-remine` marker is keyed to `targetDefect`, handled by the accelerant
336
+ * miner, not here.
337
+ */
338
+ export declare function mintAuthoredRuleId(author: string, targetDefect: string, existingIds: ReadonlySet<string>): string;
339
+ /**
340
+ * The authored producer's compile-stage input — what `toCompileFeed` builds for
341
+ * `runCompileStage`. Deliberately NOT a `ClassifyStageResult`: an authored rule
342
+ * has no mining emission ledger, so faking one would be a provenance lie. The
343
+ * classifier ledger it carries records `dispositionSource: 'authored-whitelist'`.
344
+ */
345
+ export interface AuthoredCompileFeed {
346
+ candidates: CompileInputCandidate[];
347
+ classifierLedger: ClassifierLedger;
348
+ }
349
+ /**
350
+ * ADR-112 §2/§8 — turn structurally-DECIDABLE authored rules into the input
351
+ * `runCompileStage` consumes, reusing the ONE G-series compiler (never a second).
352
+ * The disposition is set HERE to `'structural'` from the INDEPENDENT eligibility
353
+ * verdict (§3) — the author never sets it. A NON-decidable record is a contract
354
+ * violation → FAIL LOUD (the FM(d) backstop in code), never a silent skip.
355
+ * `classifierLedgerRef = authored:<authoringLedgerRef>` is unique per rule (the
356
+ * authoring ledger is 1:1 with the rule); a duplicate fails loud so the downstream
357
+ * 1:1 classifier-ledger join can't silently collapse.
358
+ */
359
+ export declare function toCompileFeed(records: readonly AuthoredRuleRecord[]): AuthoredCompileFeed;
360
+ //# sourceMappingURL=authored-rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authored-rule.d.ts","sourceRoot":"","sources":["../../src/spine/authored-rule.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,wFAAwF;AACxF,eAAO,MAAM,oBAAoB,yCAAuC,CAAC;AACzE,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAQlE;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB;;IAEjC;;;;;;;;;OASG;;;;;;;;;;;EAQH,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,+GAA+G;AAC/G,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;IAS/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAUlE;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB;IACnC;;;;;;;;;;OAUG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAMH,mFAAmF;;;QAhEnF;;;;;;;;;WASG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2DH,6FAA6F;;IAI7F,gFAAgF;;IAIhF,wEAAwE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAExE,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAI1E;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,cAAc,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE;IAAE,cAAc,EAAE,cAAc,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,EAClE,SAAS,EAAE,SAAS,cAAc,EAAE,EACpC,QAAQ,EAAE,MAAM,GACf,gBAAgB,CASlB;AAID;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,GAC/B,MAAM,CAcR;AAID;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,qBAAqB,EAAE,CAAC;IACpC,gBAAgB,EAAE,gBAAgB,CAAC;CACpC;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,GAAG,mBAAmB,CAoCzF"}
@@ -0,0 +1,199 @@
1
+ // ─── ADR-112 Gate-1 authored producer: the AuthoredRuleRecord envelope ───────
2
+ //
3
+ // The human-authored counterpart to ADR-111's mined `CandidateRuleRecord`. An
4
+ // authored rule is anchored to a real historical DEFECT (its `provenance` is the
5
+ // AUTHORED variant of the ADR-112 union — train-side preimage fixtures, §3/§4),
6
+ // carries an INDEPENDENTLY-judged structural-eligibility result (NOT author-
7
+ // asserted — §3), an accelerant-lineage marker (§7), and is minted
8
+ // `unverified`/Yellow (ADR-089) with zero enforcement blast radius.
9
+ //
10
+ // SLICE A scope: the schema spine + the deterministic eligibility check + the
11
+ // stable rule-id mint. The `totem rule author` CLI + the `.totem/spine/
12
+ // authored-rules.yaml` reader are slice B; the compile-feed integration into
13
+ // `runCompileStage` is gated on the `compileCandidate` param-widening flagged in
14
+ // the slice-A report (a controller decision). The whitelist REGISTRY of
15
+ // decidable classes lives in the CLI (slice B, mirroring `valueEqualityFieldsFor`);
16
+ // this core check takes it injected (DI), staying network-free + LLM-free.
17
+ import { createHash } from 'node:crypto';
18
+ import { z } from 'zod';
19
+ import { AuthoredProvenanceRecordSchema } from '../compiler-schema.js';
20
+ /** The matcher engines an authored rule may declare (mirrors `CompiledRule.engine`). */
21
+ export const DeclaredEngineSchema = z.enum(['regex', 'ast', 'ast-grep']);
22
+ // The §3 eligibility-basis forms: `whitelist:<class>` (the cert-#1 deterministic basis,
23
+ // a non-empty class after the colon), or the deferred `capability-check` /
24
+ // `draft-classifier+stage4`. Pins `basis` to the contract so a free-form/typo'd value
25
+ // can't validate (strategy item 2, #2259).
26
+ const ELIGIBILITY_BASIS_RE = /^(?:whitelist:.+|capability-check|draft-classifier\+stage4)$/;
27
+ /**
28
+ * ADR-112 §3 — the result of the INDEPENDENT structural-eligibility check.
29
+ * Produced by `evaluateStructuralEligibility` (NOT by the author): only
30
+ * `decidable: true` reaches the compiler, mapping to the compiler's
31
+ * `classifierDisposition: 'structural'`. `judgedBy` records who/what judged it
32
+ * (ledger-recorded, never the author), so a human cannot smuggle a behavioral
33
+ * policy past ADR-091's gate by hand-asserting "structural" (FM(d)).
34
+ */
35
+ export const StructEligResultSchema = z.object({
36
+ decidable: z.boolean(),
37
+ /**
38
+ * `whitelist:<class>` for the cert-#1 static-whitelist basis; the
39
+ * `capability-check` / `draft-classifier+stage4` bases are contract-legal but
40
+ * deferred (slice-A uses the deterministic whitelist only). On a `decidable:
41
+ * false` verdict the basis still names the attempted whitelist class — the
42
+ * diagnostic is "no/ambiguous whitelist match", carried in `judgedBy`'s log.
43
+ * Constrained to the §3 forms (strategy item 2, #2259) so a typo'd/free-form
44
+ * basis can't validate — non-mutating (no `.trim()`), matching the hash-stability
45
+ * discipline on the other reference fields.
46
+ */
47
+ basis: z.string().refine((s) => ELIGIBILITY_BASIS_RE.test(s), {
48
+ message: 'basis must be a §3 eligibility basis: whitelist:<class> | capability-check | draft-classifier+stage4',
49
+ }),
50
+ judgedBy: z.string().refine((s) => s.trim().length > 0, {
51
+ message: 'judgedBy must name the check/agent that judged eligibility (never the author)',
52
+ }),
53
+ });
54
+ /** ADR-112 §3/§7 — accelerant-lineage marker. A mined hint that informed a human is recorded, never erased. */
55
+ export const AuthoredOriginSchema = z.union([
56
+ z.object({ kind: z.literal('from-scratch') }),
57
+ z.object({
58
+ kind: z.literal('mined-accelerant'),
59
+ sourceRunId: z.string().refine((s) => s.trim().length > 0, { message: 'sourceRunId required' }),
60
+ suggestionHash: z.string().refine((s) => s.trim().length > 0, {
61
+ message: 'suggestionHash required',
62
+ }),
63
+ }),
64
+ ]);
65
+ // The persisted minted-rule-id shape (ADR-112 §8): a 16-char lowercase-hex base from
66
+ // `mintAuthoredRuleId`, with an optional collision suffix. The suffix is EXACTLY what the
67
+ // mint emits — `-<n>` for n≥1, never `-0` and never zero-padded — so schema-valid ≡
68
+ // mint-producible (#2259 CR: a looser `-\d+` admitted ids like `…-0`/`…-01` the mint can't
69
+ // make). Pinned as a shared constant binding the SCHEMA boundary to the mint's codomain.
70
+ const AUTHORED_RULE_ID_HEX_LEN = 16;
71
+ const AUTHORED_RULE_ID_RE = new RegExp(`^[0-9a-f]{${AUTHORED_RULE_ID_HEX_LEN}}(?:-[1-9]\\d*)?$`);
72
+ /**
73
+ * ADR-112 §3 — the authored producer's sole output envelope. Parallel to
74
+ * ADR-111's `CandidateRuleRecord` but carrying the AUTHORED provenance variant,
75
+ * the INDEPENDENTLY-judged eligibility result, and the accelerant lineage.
76
+ * Minted `unverified: true` (ADR-089) — zero enforcement blast radius.
77
+ */
78
+ export const AuthoredRuleRecordSchema = z.object({
79
+ /**
80
+ * ADR-112 §3/§8 — the stable, minted rule identity (`mintAuthoredRuleId`),
81
+ * assigned ONCE at authoring time and PERSISTED on the record; NEVER re-derived
82
+ * from content at read time. `firingLabelId` + the §5.3
83
+ * `controls.positive[].targetRuleId` ground-truth labels embed it, so a
84
+ * content-re-derived id would orphan them (§8). Slice A reserves the field (this
85
+ * IS the schema spine); the authoring flow (slice B) mints it, and threading it
86
+ * into the compiled artifact's identity (`firingLabelId ← ruleId`, replacing the
87
+ * `dslSource`-derived `lessonHash`) is slice C/D. The RESOLVED id (with any `-N`
88
+ * collision suffix) is what is stored.
89
+ */
90
+ ruleId: z.string().regex(AUTHORED_RULE_ID_RE, {
91
+ message: 'ruleId must be a minted authored rule id — 16 hex chars + optional -<n> suffix (ADR-112 §3/§8)',
92
+ }),
93
+ provenance: AuthoredProvenanceRecordSchema,
94
+ /** INDEPENDENTLY established (§3) — the author never sets this; the check does. */
95
+ structuralEligibility: StructEligResultSchema,
96
+ origin: AuthoredOriginSchema,
97
+ declaredEngine: DeclaredEngineSchema,
98
+ /** Reference to the §8 authoring-ledger entry (author/date/engine/splitRef/attestations). */
99
+ authoringLedgerRef: z.string().refine((s) => s.trim().length > 0, {
100
+ message: 'authoringLedgerRef must be a non-empty ledger reference',
101
+ }),
102
+ /** The human-written matcher (same DSL the compiler accepts from the miner). */
103
+ dslSource: z.string().refine((s) => s.trim().length > 0, {
104
+ message: 'dslSource must be non-empty',
105
+ }),
106
+ /** Zero-trust mint (ADR-089 / ADR-112 §1) — always literally `true`. */
107
+ unverified: z.literal(true),
108
+ });
109
+ /**
110
+ * ADR-112 §3 — the INDEPENDENT structural-eligibility check. A CLOSED registry
111
+ * predicate, NOT prose: `decidable` is true iff EXACTLY ONE whitelist entry
112
+ * matches `(declaredEngine, structuralClass)`. Unknown class, unsupported
113
+ * engine, or multiple matches → `decidable: false` (NO default-to-structural).
114
+ * The author supplies `declaredEngine` + `structuralClass`; this check OWNS the
115
+ * verdict — any author-supplied disposition is irrelevant here (FM(d)).
116
+ * Deterministic + pure (no IO, no LLM) — the same input always yields the same
117
+ * verdict (Tenet-15).
118
+ */
119
+ export function evaluateStructuralEligibility(input, whitelist, judgedBy) {
120
+ const matches = whitelist.filter((e) => e.engine === input.declaredEngine && e.structuralClass === input.structuralClass);
121
+ return {
122
+ decidable: matches.length === 1,
123
+ basis: `whitelist:${input.structuralClass}`,
124
+ judgedBy,
125
+ };
126
+ }
127
+ // ── Stable rule-id mint (ADR-112 §8) ──────────────────────────────────────────
128
+ /**
129
+ * ADR-112 §8 — mint a stable, deterministic authored rule-id. The seed is
130
+ * `sha256(JSON.stringify([author, targetDefect]))[:16]` (an INJECTIVE encoding —
131
+ * see the inline note) — `dslSource` is DELIBERATELY EXCLUDED so an author can
132
+ * tighten/refactor the matcher without orphaning the rule's ledger history. On collision with an already-resolved id (two rules sharing the same
133
+ * `(author, targetDefect)`), a stable `-N` counter is appended. The RESOLVED id
134
+ * is what callers persist — never recompute the raw seed at read time, or a
135
+ * later sibling could shift the suffix (the gemini/agy break). The
136
+ * `never-remine` marker is keyed to `targetDefect`, handled by the accelerant
137
+ * miner, not here.
138
+ */
139
+ export function mintAuthoredRuleId(author, targetDefect, existingIds) {
140
+ // Unambiguous seed encoding (GCA-high + CR-major, #2259): a bare `author·targetDefect`
141
+ // ALIASES distinct tuples — ('a·b','c') and ('a','b·c') collapse onto one seed. A JSON
142
+ // array of the two inputs is injective: distinct (author, targetDefect) pairs can never
143
+ // serialize to the same string, so a persisted id can't collide by encoding.
144
+ const seed = createHash('sha256')
145
+ .update(JSON.stringify([author, targetDefect]))
146
+ .digest('hex')
147
+ .slice(0, AUTHORED_RULE_ID_HEX_LEN);
148
+ if (!existingIds.has(seed))
149
+ return seed;
150
+ for (let n = 1;; n += 1) {
151
+ const candidate = `${seed}-${n}`;
152
+ if (!existingIds.has(candidate))
153
+ return candidate;
154
+ }
155
+ }
156
+ /**
157
+ * ADR-112 §2/§8 — turn structurally-DECIDABLE authored rules into the input
158
+ * `runCompileStage` consumes, reusing the ONE G-series compiler (never a second).
159
+ * The disposition is set HERE to `'structural'` from the INDEPENDENT eligibility
160
+ * verdict (§3) — the author never sets it. A NON-decidable record is a contract
161
+ * violation → FAIL LOUD (the FM(d) backstop in code), never a silent skip.
162
+ * `classifierLedgerRef = authored:<authoringLedgerRef>` is unique per rule (the
163
+ * authoring ledger is 1:1 with the rule); a duplicate fails loud so the downstream
164
+ * 1:1 classifier-ledger join can't silently collapse.
165
+ */
166
+ export function toCompileFeed(records) {
167
+ const candidates = [];
168
+ const entries = [];
169
+ const seen = new Set();
170
+ for (const record of records) {
171
+ if (!record.structuralEligibility.decidable) {
172
+ throw new Error(`[Totem Error] toCompileFeed: authored rule '${record.authoringLedgerRef}' is not structurally decidable — a non-decidable rule must never reach the compiler (ADR-112 §3 / FM(d))`);
173
+ }
174
+ const classifierLedgerRef = `authored:${record.authoringLedgerRef}`;
175
+ if (seen.has(classifierLedgerRef)) {
176
+ throw new Error(`[Totem Error] toCompileFeed: duplicate authoringLedgerRef '${record.authoringLedgerRef}' — each authored rule needs a unique ledger ref for the 1:1 compile join`);
177
+ }
178
+ seen.add(classifierLedgerRef);
179
+ candidates.push({
180
+ provenance: record.provenance,
181
+ classifierDisposition: 'structural',
182
+ classifierLedgerRef,
183
+ dslSource: record.dslSource,
184
+ // §3 (#7): carry the whitelist-judged engine so the compiler can assert it
185
+ // compiled under THAT engine — a regex-whitelisted rule whose dslSource parses
186
+ // as ast-grep must fail loud, not silently re-route to a different engine.
187
+ declaredEngine: record.declaredEngine,
188
+ unverified: true,
189
+ });
190
+ entries.push({
191
+ candidateRef: classifierLedgerRef,
192
+ disposition: 'structural',
193
+ stage4Confirmed: false,
194
+ dispositionSource: 'authored-whitelist',
195
+ });
196
+ }
197
+ return { candidates, classifierLedger: { entries } };
198
+ }
199
+ //# sourceMappingURL=authored-rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authored-rule.js","sourceRoot":"","sources":["../../src/spine/authored-rule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=authored-rule.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authored-rule.test.d.ts","sourceRoot":"","sources":["../../src/spine/authored-rule.test.ts"],"names":[],"mappings":""}