@mmnto/totem 1.82.0 → 1.83.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/spine/authored-controls.d.ts +245 -0
- package/dist/spine/authored-controls.d.ts.map +1 -0
- package/dist/spine/authored-controls.js +291 -0
- package/dist/spine/authored-controls.js.map +1 -0
- package/dist/spine/authored-controls.test.d.ts +2 -0
- package/dist/spine/authored-controls.test.d.ts.map +1 -0
- package/dist/spine/authored-controls.test.js +441 -0
- package/dist/spine/authored-controls.test.js.map +1 -0
- package/dist/spine/rule-policy.d.ts +8 -0
- package/dist/spine/rule-policy.d.ts.map +1 -1
- package/dist/spine/rule-policy.js +2 -0
- package/dist/spine/rule-policy.js.map +1 -1
- package/dist/spine/rule-policy.test.js +8 -2
- package/dist/spine/rule-policy.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { AuthoredNonEmissionSchema, deriveAuthoredControls, } from './authored-controls.js';
|
|
3
|
+
import { getRulePolicy } from './rule-policy.js';
|
|
4
|
+
import { resolveSplit, SplitCoverError } from './split.js';
|
|
5
|
+
// Wrap the two cross-module seams in pass-through spies (mirrors compile.test.ts):
|
|
6
|
+
// - `resolveSplit` — to assert deriveAuthoredControls NEVER routes through it (the
|
|
7
|
+
// train-side controls use a SEPARATE path); the mirror test still calls the real
|
|
8
|
+
// impl (vi.fn passes through to `actual`).
|
|
9
|
+
// - `getRulePolicy` — to drive the §9 producer-mismatch fail-loud guards with a
|
|
10
|
+
// one-shot wrong policy; every other test passes through to the real frozen one.
|
|
11
|
+
vi.mock('./split.js', async (importOriginal) => {
|
|
12
|
+
const actual = await importOriginal();
|
|
13
|
+
return { ...actual, resolveSplit: vi.fn(actual.resolveSplit) };
|
|
14
|
+
});
|
|
15
|
+
vi.mock('./rule-policy.js', async (importOriginal) => {
|
|
16
|
+
const actual = await importOriginal();
|
|
17
|
+
return { ...actual, getRulePolicy: vi.fn(actual.getRulePolicy) };
|
|
18
|
+
});
|
|
19
|
+
// ─── Constants ──────────────────────────────────────
|
|
20
|
+
/** A 16-hex `hashLesson` codomain id (the lesson preimageSource's immutable ref). */
|
|
21
|
+
const LESSON_REF = 'deadbeefdeadbeef';
|
|
22
|
+
/** Per-index delay unit for the determinism probe (slow-FIRST). */
|
|
23
|
+
const DELAY_UNIT_MS = 4;
|
|
24
|
+
const sha = (n) => String(n).padStart(40, '0');
|
|
25
|
+
// ─── Fixture / rule helpers ─────────────────────────
|
|
26
|
+
function posFixture(pr, contentHash, filePath = 'src/a.ts') {
|
|
27
|
+
return {
|
|
28
|
+
pr,
|
|
29
|
+
preimageSource: {
|
|
30
|
+
kind: 'lesson',
|
|
31
|
+
lessonRef: LESSON_REF,
|
|
32
|
+
badExample: 'bad()',
|
|
33
|
+
goodExample: 'good()',
|
|
34
|
+
},
|
|
35
|
+
filePath,
|
|
36
|
+
matchedSpan: 'L1-L2',
|
|
37
|
+
contentHash,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function negFixture(filePath, matchedSpan) {
|
|
41
|
+
return {
|
|
42
|
+
filePath,
|
|
43
|
+
matchedSpan,
|
|
44
|
+
nearMissSource: { kind: 'lesson', example: 'nearMiss()' },
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function authoredRule(lessonHash, positiveFixtures, negativeFixtures) {
|
|
48
|
+
const provenance = {
|
|
49
|
+
kind: 'authored',
|
|
50
|
+
author: 'agent-x',
|
|
51
|
+
authoredAt: '2026-06-01',
|
|
52
|
+
targetDefect: 'a real lc defect',
|
|
53
|
+
positiveFixtures,
|
|
54
|
+
...(negativeFixtures ? { negativeFixtures } : {}),
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
lessonHash,
|
|
58
|
+
lessonHeading: 'Authored rule',
|
|
59
|
+
pattern: 'bad',
|
|
60
|
+
message: 'no bad',
|
|
61
|
+
engine: 'regex',
|
|
62
|
+
compiledAt: '2026-06-01T00:00:00Z',
|
|
63
|
+
legitimacy: { provenance, positiveControl: true, negativeControl: true },
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** A minimal valid SplitArtifact — only `trainPrs` is read by the builder. */
|
|
67
|
+
function splitWithTrain(trainPrs, heldOutPrs = []) {
|
|
68
|
+
return {
|
|
69
|
+
asOfCommit: sha(999),
|
|
70
|
+
trainPrs,
|
|
71
|
+
heldOutPrs,
|
|
72
|
+
excludedPrs: [],
|
|
73
|
+
positiveControlPrs: [],
|
|
74
|
+
negativeControlPrs: [],
|
|
75
|
+
splitRule: { predicate: 'code-touching non-bot', cutIndex: Math.max(trainPrs.length, 1) },
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// ─── Differential-evaluator stubs (no git, no engine) ─
|
|
79
|
+
function makeResult(outcome, reason) {
|
|
80
|
+
return {
|
|
81
|
+
outcome,
|
|
82
|
+
sourceKind: 'lesson',
|
|
83
|
+
firesOnPreimage: null,
|
|
84
|
+
silentOnPostimage: null,
|
|
85
|
+
preimageMatchCount: null,
|
|
86
|
+
postimageMatchCount: null,
|
|
87
|
+
...(reason !== undefined ? { reason } : {}),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/** Scripts a differential result per fixture (keyed on its unique contentHash). */
|
|
91
|
+
function scriptedDeps(byContentHash) {
|
|
92
|
+
return {
|
|
93
|
+
evaluate: (_rule, fixture) => {
|
|
94
|
+
const result = byContentHash[fixture.contentHash];
|
|
95
|
+
if (result === undefined) {
|
|
96
|
+
throw new Error(`test stub: no scripted result for contentHash '${fixture.contentHash}'`);
|
|
97
|
+
}
|
|
98
|
+
return Promise.resolve(result);
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** An evaluator that throws if ever invoked — proves negatives never run the differential. */
|
|
103
|
+
const throwingDeps = {
|
|
104
|
+
evaluate: () => {
|
|
105
|
+
throw new Error('the §4 differential must not run for negative (silence-only) controls');
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
/** Slow-FIRST delays: the earliest task waits the longest, so a push-on-settle impl would reorder. */
|
|
109
|
+
function slowFirstDeps(total) {
|
|
110
|
+
let calls = 0;
|
|
111
|
+
return {
|
|
112
|
+
evaluate: (_rule, _fixture) => {
|
|
113
|
+
const idx = calls++;
|
|
114
|
+
const delayMs = (total - idx) * DELAY_UNIT_MS;
|
|
115
|
+
return new Promise((resolve) => setTimeout(() => resolve(makeResult('differential-holds')), delayMs));
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// ─── 1. Per-outcome matrix (the §4 gate, exact-equality both directions) ─────
|
|
120
|
+
describe('deriveAuthoredControls — per-outcome matrix', () => {
|
|
121
|
+
it('emits a positive ONLY for differential-holds; the other 5 outcomes become classed non-emissions', async () => {
|
|
122
|
+
const rule = authoredRule('rule-auth-1', [
|
|
123
|
+
posFixture(1, 'ch-holds'),
|
|
124
|
+
posFixture(2, 'ch-fix'),
|
|
125
|
+
posFixture(3, 'ch-over'),
|
|
126
|
+
posFixture(4, 'ch-vac'),
|
|
127
|
+
posFixture(5, 'ch-needs'),
|
|
128
|
+
posFixture(6, 'ch-unsup'),
|
|
129
|
+
]);
|
|
130
|
+
const deps = scriptedDeps({
|
|
131
|
+
'ch-holds': makeResult('differential-holds'),
|
|
132
|
+
'ch-fix': makeResult('fix-shaped'),
|
|
133
|
+
'ch-over': makeResult('over-match'),
|
|
134
|
+
'ch-vac': makeResult('vacuous-silent'),
|
|
135
|
+
'ch-needs': makeResult('needs-adjudication', 'engine refused: invalid regex'),
|
|
136
|
+
'ch-unsup': makeResult('unsupported-source', 'commit-pair source deferred to a later slice'),
|
|
137
|
+
});
|
|
138
|
+
const result = await deriveAuthoredControls({
|
|
139
|
+
rules: [rule],
|
|
140
|
+
split: splitWithTrain([1, 2, 3, 4, 5, 6]),
|
|
141
|
+
deps,
|
|
142
|
+
});
|
|
143
|
+
// Exactly ONE positive — the holds fixture, carrying ITS locus. This kills
|
|
144
|
+
// the `outcome !== 'fix-shaped'` mutant (which would emit 5 positives).
|
|
145
|
+
expect(result.positive).toEqual([
|
|
146
|
+
{ pr: 1, targetRuleId: 'rule-auth-1', filePath: 'src/a.ts', matchedSpan: 'L1-L2' },
|
|
147
|
+
]);
|
|
148
|
+
// The other five are KEPT (never silently dropped) with the exact source outcome
|
|
149
|
+
// + the correct class.
|
|
150
|
+
expect(result.nonEmissions).toHaveLength(5);
|
|
151
|
+
const byOutcome = new Map(result.nonEmissions.map((n) => [n.outcome, n]));
|
|
152
|
+
expect(byOutcome.get('fix-shaped')).toEqual({
|
|
153
|
+
targetRuleId: 'rule-auth-1',
|
|
154
|
+
pr: 2,
|
|
155
|
+
outcome: 'fix-shaped',
|
|
156
|
+
class: 'illegitimate',
|
|
157
|
+
});
|
|
158
|
+
expect(byOutcome.get('over-match')).toEqual({
|
|
159
|
+
targetRuleId: 'rule-auth-1',
|
|
160
|
+
pr: 3,
|
|
161
|
+
outcome: 'over-match',
|
|
162
|
+
class: 'illegitimate',
|
|
163
|
+
});
|
|
164
|
+
expect(byOutcome.get('vacuous-silent')).toEqual({
|
|
165
|
+
targetRuleId: 'rule-auth-1',
|
|
166
|
+
pr: 4,
|
|
167
|
+
outcome: 'vacuous-silent',
|
|
168
|
+
class: 'illegitimate',
|
|
169
|
+
});
|
|
170
|
+
expect(byOutcome.get('needs-adjudication')).toEqual({
|
|
171
|
+
targetRuleId: 'rule-auth-1',
|
|
172
|
+
pr: 5,
|
|
173
|
+
outcome: 'needs-adjudication',
|
|
174
|
+
class: 'undecidable',
|
|
175
|
+
reason: 'engine refused: invalid regex',
|
|
176
|
+
});
|
|
177
|
+
expect(byOutcome.get('unsupported-source')).toEqual({
|
|
178
|
+
targetRuleId: 'rule-auth-1',
|
|
179
|
+
pr: 6,
|
|
180
|
+
outcome: 'unsupported-source',
|
|
181
|
+
class: 'deferred',
|
|
182
|
+
reason: 'commit-pair source deferred to a later slice',
|
|
183
|
+
});
|
|
184
|
+
// Exact-equality, the OTHER direction: NONE of the 5 non-holds outcomes leaked
|
|
185
|
+
// into positives (the holds one is the sole positive).
|
|
186
|
+
expect(result.positive.map((p) => p.pr)).toEqual([1]);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
// ─── 2. Two-loci-one-PR disambiguation (strategy#777 Q1(a)) ──────────────────
|
|
190
|
+
describe('deriveAuthoredControls — two-loci-one-PR disambiguation', () => {
|
|
191
|
+
it('a PR contributing two distinct-locus fixtures emits ONLY the holding one, carrying ITS locus', async () => {
|
|
192
|
+
const rule = authoredRule('rule-2loci', [
|
|
193
|
+
posFixture(7, 'ch-A', 'src/a.ts'),
|
|
194
|
+
posFixture(7, 'ch-B', 'src/b.ts'),
|
|
195
|
+
]);
|
|
196
|
+
const deps = scriptedDeps({
|
|
197
|
+
'ch-A': makeResult('differential-holds'),
|
|
198
|
+
'ch-B': makeResult('fix-shaped'),
|
|
199
|
+
});
|
|
200
|
+
const result = await deriveAuthoredControls({
|
|
201
|
+
rules: [rule],
|
|
202
|
+
split: splitWithTrain([7]),
|
|
203
|
+
deps,
|
|
204
|
+
});
|
|
205
|
+
// The positive carries the src/a.ts locus (the holding fixture) — NOT src/b.ts; the
|
|
206
|
+
// locus disambiguator prevents the wrong-exemplar miscert under a shared pr.
|
|
207
|
+
expect(result.positive).toEqual([
|
|
208
|
+
{ pr: 7, targetRuleId: 'rule-2loci', filePath: 'src/a.ts', matchedSpan: 'L1-L2' },
|
|
209
|
+
]);
|
|
210
|
+
expect(result.nonEmissions).toEqual([
|
|
211
|
+
{ targetRuleId: 'rule-2loci', pr: 7, outcome: 'fix-shaped', class: 'illegitimate' },
|
|
212
|
+
]);
|
|
213
|
+
});
|
|
214
|
+
// strategy#777 §6: the LOCUS (filePath, matchedSpan) is the disambiguator, so two
|
|
215
|
+
// HOLDING fixtures in one PR at DISTINCT loci both emit — even with byte-identical
|
|
216
|
+
// span content (same contentHash). This is the legitimate two-loci-one-PR rule the
|
|
217
|
+
// old contentHash key wrongly FORBADE; emitting two is the whole point of the fix.
|
|
218
|
+
it('emits TWO positives for two HOLDING fixtures sharing a PR at distinct loci (even identical content)', async () => {
|
|
219
|
+
const rule = authoredRule('rule-2loci-hold', [
|
|
220
|
+
posFixture(7, 'ch-same', 'src/a.ts'),
|
|
221
|
+
posFixture(7, 'ch-same', 'src/b.ts'),
|
|
222
|
+
]);
|
|
223
|
+
const result = await deriveAuthoredControls({
|
|
224
|
+
rules: [rule],
|
|
225
|
+
split: splitWithTrain([7]),
|
|
226
|
+
deps: scriptedDeps({ 'ch-same': makeResult('differential-holds') }),
|
|
227
|
+
});
|
|
228
|
+
expect(result.positive).toEqual([
|
|
229
|
+
{ pr: 7, targetRuleId: 'rule-2loci-hold', filePath: 'src/a.ts', matchedSpan: 'L1-L2' },
|
|
230
|
+
{ pr: 7, targetRuleId: 'rule-2loci-hold', filePath: 'src/b.ts', matchedSpan: 'L1-L2' },
|
|
231
|
+
]);
|
|
232
|
+
});
|
|
233
|
+
// A TRUE duplicate — same pr + filePath + matchedSpan — IS an indistinguishable §6
|
|
234
|
+
// answer-key entry (a real authoring error, not the two-loci rule): fail loud,
|
|
235
|
+
// regardless of content hash (here the two fixtures even differ in contentHash).
|
|
236
|
+
it('throws when two HOLDING fixtures share pr AND filePath AND matchedSpan (same locus)', async () => {
|
|
237
|
+
const rule = authoredRule('rule-dup-pos', [
|
|
238
|
+
posFixture(7, 'ch-x', 'src/a.ts'),
|
|
239
|
+
posFixture(7, 'ch-y', 'src/a.ts'),
|
|
240
|
+
]);
|
|
241
|
+
await expect(deriveAuthoredControls({
|
|
242
|
+
rules: [rule],
|
|
243
|
+
split: splitWithTrain([7]),
|
|
244
|
+
deps: scriptedDeps({
|
|
245
|
+
'ch-x': makeResult('differential-holds'),
|
|
246
|
+
'ch-y': makeResult('differential-holds'),
|
|
247
|
+
}),
|
|
248
|
+
})).rejects.toThrow(/duplicate positive control/);
|
|
249
|
+
});
|
|
250
|
+
it('throws when two near-misses share filePath AND matchedSpan (indistinguishable negative key)', async () => {
|
|
251
|
+
const rule = authoredRule('rule-dup-neg', [posFixture(1, 'ch-1')], [negFixture('src/a.ts', 'L1-L2'), negFixture('src/a.ts', 'L1-L2')]);
|
|
252
|
+
await expect(deriveAuthoredControls({
|
|
253
|
+
rules: [rule],
|
|
254
|
+
split: splitWithTrain([1]),
|
|
255
|
+
deps: scriptedDeps({ 'ch-1': makeResult('differential-holds') }),
|
|
256
|
+
})).rejects.toThrow(/duplicate negative control/);
|
|
257
|
+
});
|
|
258
|
+
// greptile P2 regression guard: the join-key is `JSON.stringify([...])`, NOT a
|
|
259
|
+
// `\0`-joined template — so two DISTINCT loci that merely shift the delimiter
|
|
260
|
+
// boundary (filePath 'a.ts' + span 'L1\0L2' vs filePath 'a.ts\0L1' + span 'L2')
|
|
261
|
+
// no longer collide into ONE key. Both emit; the old delimited key falsely threw
|
|
262
|
+
// "duplicate" on a load-bearing D-join target.
|
|
263
|
+
it('distinct negative loci with an embedded delimiter do NOT collide (injection-proof key)', async () => {
|
|
264
|
+
const rule = authoredRule('rule-delim-neg', [posFixture(1, 'ch-1')], [negFixture('a.ts', 'L1\0L2'), negFixture('a.ts\0L1', 'L2')]);
|
|
265
|
+
const result = await deriveAuthoredControls({
|
|
266
|
+
rules: [rule],
|
|
267
|
+
split: splitWithTrain([1]),
|
|
268
|
+
deps: scriptedDeps({ 'ch-1': makeResult('differential-holds') }),
|
|
269
|
+
});
|
|
270
|
+
expect(result.negative).toEqual([
|
|
271
|
+
{ targetRuleId: 'rule-delim-neg', filePath: 'a.ts', matchedSpan: 'L1\0L2' },
|
|
272
|
+
{ targetRuleId: 'rule-delim-neg', filePath: 'a.ts\0L1', matchedSpan: 'L2' },
|
|
273
|
+
]);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
// ─── 3. Determinism (Tenet-15; slow-first must NOT reorder) ──────────────────
|
|
277
|
+
describe('deriveAuthoredControls — determinism', () => {
|
|
278
|
+
it('emits in stable declared order regardless of settle timing, byte-identical across re-runs', async () => {
|
|
279
|
+
const contentHashes = ['ch-0', 'ch-1', 'ch-2', 'ch-3'];
|
|
280
|
+
const rule = authoredRule('rule-det', contentHashes.map((ch, i) => posFixture(i + 1, ch)));
|
|
281
|
+
const split = splitWithTrain([1, 2, 3, 4]);
|
|
282
|
+
const runA = await deriveAuthoredControls({
|
|
283
|
+
rules: [rule],
|
|
284
|
+
split,
|
|
285
|
+
deps: slowFirstDeps(contentHashes.length),
|
|
286
|
+
});
|
|
287
|
+
const runB = await deriveAuthoredControls({
|
|
288
|
+
rules: [rule],
|
|
289
|
+
split,
|
|
290
|
+
deps: slowFirstDeps(contentHashes.length),
|
|
291
|
+
});
|
|
292
|
+
expect(runA).toEqual(runB);
|
|
293
|
+
// Declared order preserved — a push-on-settle impl with slow-first delays would
|
|
294
|
+
// invert this to [4, 3, 2, 1].
|
|
295
|
+
expect(runA.positive.map((p) => p.pr)).toEqual([1, 2, 3, 4]);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
// ─── 4. Boundary: never routes through resolveSplit ──────────────────────────
|
|
299
|
+
describe('deriveAuthoredControls — boundary vs resolveSplit', () => {
|
|
300
|
+
it('does NOT invoke resolveSplit (train-side controls use a SEPARATE path)', async () => {
|
|
301
|
+
vi.mocked(resolveSplit).mockClear();
|
|
302
|
+
const rule = authoredRule('rule-bnd', [posFixture(1, 'ch-1')]);
|
|
303
|
+
await deriveAuthoredControls({
|
|
304
|
+
rules: [rule],
|
|
305
|
+
split: splitWithTrain([1]),
|
|
306
|
+
deps: scriptedDeps({ 'ch-1': makeResult('differential-holds') }),
|
|
307
|
+
});
|
|
308
|
+
expect(vi.mocked(resolveSplit)).not.toHaveBeenCalled();
|
|
309
|
+
});
|
|
310
|
+
it('mirror: a TRAIN pr fed as a resolveSplit positive control throws (controls⊄heldOut) — WHY the separate path exists', () => {
|
|
311
|
+
const corpus = [1, 2, 3];
|
|
312
|
+
const mergeCommitByPr = new Map(corpus.map((pr) => [pr, sha(pr)]));
|
|
313
|
+
// cutIndex 2 → train [1,2], heldOut [3]; pr 1 is TRAIN, so as a positive control
|
|
314
|
+
// it violates controls ⊆ heldOut — the exact leakage the C2b path sidesteps.
|
|
315
|
+
expect(() => resolveSplit({
|
|
316
|
+
asOfCommit: sha(999),
|
|
317
|
+
corpus,
|
|
318
|
+
orderedNewestFirst: [3, 2, 1],
|
|
319
|
+
excludedPrs: [],
|
|
320
|
+
cutIndex: 2,
|
|
321
|
+
positiveControlPrs: [1],
|
|
322
|
+
negativeControlPrs: [],
|
|
323
|
+
predicate: 'code-touching',
|
|
324
|
+
mergeCommitByPr,
|
|
325
|
+
})).toThrow(SplitCoverError);
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
// ─── 5. Fail-loud guards (§5 leakage + §9 producer mismatch) ─────────────────
|
|
329
|
+
describe('deriveAuthoredControls — fail-loud guards', () => {
|
|
330
|
+
it('throws when a positive fixture pr is held-out (∉ trainPrs) — an ADR-112 §5 leakage violation', async () => {
|
|
331
|
+
const rule = authoredRule('rule-leak', [posFixture(99, 'ch-leak')]);
|
|
332
|
+
await expect(deriveAuthoredControls({
|
|
333
|
+
rules: [rule],
|
|
334
|
+
split: splitWithTrain([1, 2], [99]), // 99 is held-out, not train
|
|
335
|
+
deps: scriptedDeps({ 'ch-leak': makeResult('differential-holds') }),
|
|
336
|
+
})).rejects.toThrow(/leakage/i);
|
|
337
|
+
});
|
|
338
|
+
it('throws when authored policy.positiveControlSide is not train (§6 producer mismatch)', async () => {
|
|
339
|
+
vi.mocked(getRulePolicy).mockReturnValueOnce({
|
|
340
|
+
labelScope: 'whole-window',
|
|
341
|
+
positiveControlSide: 'held-out',
|
|
342
|
+
exposureControlSide: 'held-out',
|
|
343
|
+
positiveControlGate: 'preimage-differential',
|
|
344
|
+
});
|
|
345
|
+
const rule = authoredRule('rule-pol', [posFixture(1, 'ch-1')]);
|
|
346
|
+
await expect(deriveAuthoredControls({
|
|
347
|
+
rules: [rule],
|
|
348
|
+
split: splitWithTrain([1]),
|
|
349
|
+
deps: scriptedDeps({ 'ch-1': makeResult('differential-holds') }),
|
|
350
|
+
})).rejects.toThrow(/positiveControlSide/);
|
|
351
|
+
});
|
|
352
|
+
it('throws when authored policy.positiveControlGate is not preimage-differential (§4 producer mismatch)', async () => {
|
|
353
|
+
vi.mocked(getRulePolicy).mockReturnValueOnce({
|
|
354
|
+
labelScope: 'whole-window',
|
|
355
|
+
positiveControlSide: 'train',
|
|
356
|
+
exposureControlSide: 'train',
|
|
357
|
+
positiveControlGate: 'none',
|
|
358
|
+
});
|
|
359
|
+
const rule = authoredRule('rule-pol2', [posFixture(1, 'ch-1')]);
|
|
360
|
+
await expect(deriveAuthoredControls({
|
|
361
|
+
rules: [rule],
|
|
362
|
+
split: splitWithTrain([1]),
|
|
363
|
+
deps: scriptedDeps({ 'ch-1': makeResult('differential-holds') }),
|
|
364
|
+
})).rejects.toThrow(/positiveControlGate/);
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
// ─── 6. Negatives are DECLARATIVE (no differential, no silence gate) ─────────
|
|
368
|
+
describe('deriveAuthoredControls — declarative negatives', () => {
|
|
369
|
+
it('emits every declared near-miss as {targetRuleId,filePath,matchedSpan} WITHOUT running the evaluator', async () => {
|
|
370
|
+
const rule = authoredRule('rule-neg', [], // no positive fixtures → the evaluator must never run
|
|
371
|
+
[negFixture('src/x.ts', 'L5-L9'), negFixture('src/y.ts', 'N[2]')]);
|
|
372
|
+
// A throwing evaluator proves the §4 differential/smoke-gate is NOT invoked for
|
|
373
|
+
// negatives — a near-miss is emitted even though no evaluator runs on it.
|
|
374
|
+
const result = await deriveAuthoredControls({
|
|
375
|
+
rules: [rule],
|
|
376
|
+
split: splitWithTrain([1]),
|
|
377
|
+
deps: throwingDeps,
|
|
378
|
+
});
|
|
379
|
+
expect(result.negative).toEqual([
|
|
380
|
+
{ targetRuleId: 'rule-neg', filePath: 'src/x.ts', matchedSpan: 'L5-L9' },
|
|
381
|
+
{ targetRuleId: 'rule-neg', filePath: 'src/y.ts', matchedSpan: 'N[2]' },
|
|
382
|
+
]);
|
|
383
|
+
expect(result.positive).toEqual([]);
|
|
384
|
+
expect(result.nonEmissions).toEqual([]);
|
|
385
|
+
});
|
|
386
|
+
it('emits negatives alongside positives in stable rule/declared order', async () => {
|
|
387
|
+
const rule = authoredRule('rule-mixed', [posFixture(1, 'ch-1')], [negFixture('src/n.ts', 'L1')]);
|
|
388
|
+
const result = await deriveAuthoredControls({
|
|
389
|
+
rules: [rule],
|
|
390
|
+
split: splitWithTrain([1]),
|
|
391
|
+
deps: scriptedDeps({ 'ch-1': makeResult('differential-holds') }),
|
|
392
|
+
});
|
|
393
|
+
expect(result.positive).toEqual([
|
|
394
|
+
{ pr: 1, targetRuleId: 'rule-mixed', filePath: 'src/a.ts', matchedSpan: 'L1-L2' },
|
|
395
|
+
]);
|
|
396
|
+
expect(result.negative).toEqual([
|
|
397
|
+
{ targetRuleId: 'rule-mixed', filePath: 'src/n.ts', matchedSpan: 'L1' },
|
|
398
|
+
]);
|
|
399
|
+
});
|
|
400
|
+
});
|
|
401
|
+
// ─── 7. positiveControlGate present + frozen on both policies ────────────────
|
|
402
|
+
describe('positiveControlGate — present + frozen (§4 / strategy#777 Q3(ii))', () => {
|
|
403
|
+
it('mined gate is none, authored gate is preimage-differential', () => {
|
|
404
|
+
expect(getRulePolicy('mined').positiveControlGate).toBe('none');
|
|
405
|
+
expect(getRulePolicy('authored').positiveControlGate).toBe('preimage-differential');
|
|
406
|
+
});
|
|
407
|
+
it('the policy is frozen — a caller cannot flip the gate process-wide', () => {
|
|
408
|
+
const policy = getRulePolicy('authored');
|
|
409
|
+
expect(Object.isFrozen(policy)).toBe(true);
|
|
410
|
+
expect(() => Object.assign(policy, { positiveControlGate: 'none' })).toThrow();
|
|
411
|
+
});
|
|
412
|
+
it('deriveAuthoredControls reads the (real) authored policy and completes on valid input', async () => {
|
|
413
|
+
const rule = authoredRule('rule-ok', [posFixture(1, 'ch-1')]);
|
|
414
|
+
const result = await deriveAuthoredControls({
|
|
415
|
+
rules: [rule],
|
|
416
|
+
split: splitWithTrain([1]),
|
|
417
|
+
deps: scriptedDeps({ 'ch-1': makeResult('differential-holds') }),
|
|
418
|
+
});
|
|
419
|
+
expect(result.positive).toHaveLength(1);
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
// ─── Exported boundary guard (CR outside-diff): the schema must reject what the
|
|
423
|
+
// trichotomy makes structurally impossible, not merely admit any enum member. ──
|
|
424
|
+
describe('AuthoredNonEmissionSchema — outcome/class boundary guard', () => {
|
|
425
|
+
const base = { targetRuleId: 'rule-x', pr: 1, outcome: 'fix-shaped', class: 'illegitimate' };
|
|
426
|
+
it('accepts a well-formed non-emission (outcome → its classOf class)', () => {
|
|
427
|
+
expect(AuthoredNonEmissionSchema.safeParse(base).success).toBe(true);
|
|
428
|
+
});
|
|
429
|
+
it('rejects the EMITTING outcome — a non-emission can never carry differential-holds', () => {
|
|
430
|
+
expect(AuthoredNonEmissionSchema.safeParse({ ...base, outcome: 'differential-holds' }).success).toBe(false);
|
|
431
|
+
});
|
|
432
|
+
it('rejects a class that contradicts its outcome (classOf mismatch)', () => {
|
|
433
|
+
// needs-adjudication is `undecidable`, never `illegitimate`.
|
|
434
|
+
expect(AuthoredNonEmissionSchema.safeParse({
|
|
435
|
+
...base,
|
|
436
|
+
outcome: 'needs-adjudication',
|
|
437
|
+
class: 'illegitimate',
|
|
438
|
+
}).success).toBe(false);
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
//# sourceMappingURL=authored-controls.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authored-controls.test.js","sourceRoot":"","sources":["../../src/spine/authored-controls.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,11 +12,19 @@ export type ProducerKind = 'mined' | 'authored';
|
|
|
12
12
|
* authored against the train slice).
|
|
13
13
|
* - `exposureControlSide` — §5.3: which slice `positiveControlsExercised`
|
|
14
14
|
* counts. Mirrors `positiveControlSide`.
|
|
15
|
+
* - `positiveControlGate` — §4 (strategy#777 Q3(ii)): how a positive control is
|
|
16
|
+
* admitted. Mined controls are corpus-firing evidence
|
|
17
|
+
* (`none`); authored controls must clear the
|
|
18
|
+
* preimage-differential gate (fire-on-preimage /
|
|
19
|
+
* silent-on-postimage). FROZEN-ENUM DATA only — no
|
|
20
|
+
* consumer branches on the table itself (Tenet 9); the
|
|
21
|
+
* authored-controls builder READS it as the §9 home.
|
|
15
22
|
*/
|
|
16
23
|
export interface RulePolicy {
|
|
17
24
|
readonly labelScope: 'held-out-only' | 'whole-window';
|
|
18
25
|
readonly positiveControlSide: 'held-out' | 'train';
|
|
19
26
|
readonly exposureControlSide: 'held-out' | 'train';
|
|
27
|
+
readonly positiveControlGate: 'none' | 'preimage-differential';
|
|
20
28
|
}
|
|
21
29
|
/**
|
|
22
30
|
* ADR-112 §9 — resolve the override config for a producer kind. Pure +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-policy.d.ts","sourceRoot":"","sources":["../../src/spine/rule-policy.ts"],"names":[],"mappings":"AAgBA,8EAA8E;AAC9E,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,UAAU,CAAC;AAEhD
|
|
1
|
+
{"version":3,"file":"rule-policy.d.ts","sourceRoot":"","sources":["../../src/spine/rule-policy.ts"],"names":[],"mappings":"AAgBA,8EAA8E;AAC9E,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,UAAU,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,UAAU;IAIzB,QAAQ,CAAC,UAAU,EAAE,eAAe,GAAG,cAAc,CAAC;IACtD,QAAQ,CAAC,mBAAmB,EAAE,UAAU,GAAG,OAAO,CAAC;IACnD,QAAQ,CAAC,mBAAmB,EAAE,UAAU,GAAG,OAAO,CAAC;IACnD,QAAQ,CAAC,mBAAmB,EAAE,MAAM,GAAG,uBAAuB,CAAC;CAChE;AAgBD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,UAAU,CAa5D"}
|
|
@@ -17,11 +17,13 @@ const MINED_POLICY = Object.freeze({
|
|
|
17
17
|
labelScope: 'held-out-only',
|
|
18
18
|
positiveControlSide: 'held-out',
|
|
19
19
|
exposureControlSide: 'held-out',
|
|
20
|
+
positiveControlGate: 'none',
|
|
20
21
|
});
|
|
21
22
|
const AUTHORED_POLICY = Object.freeze({
|
|
22
23
|
labelScope: 'whole-window',
|
|
23
24
|
positiveControlSide: 'train',
|
|
24
25
|
exposureControlSide: 'train',
|
|
26
|
+
positiveControlGate: 'preimage-differential',
|
|
25
27
|
});
|
|
26
28
|
/**
|
|
27
29
|
* ADR-112 §9 — resolve the override config for a producer kind. Pure +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-policy.js","sourceRoot":"","sources":["../../src/spine/rule-policy.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,kFAAkF;AAClF,+EAA+E;AAC/E,iEAAiE;AACjE,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF,0EAA0E;AAC1E,4EAA4E;AAC5E,6EAA6E;AAC7E,8EAA8E;AAC9E,iFAAiF;
|
|
1
|
+
{"version":3,"file":"rule-policy.js","sourceRoot":"","sources":["../../src/spine/rule-policy.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,kFAAkF;AAClF,+EAA+E;AAC/E,iEAAiE;AACjE,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF,0EAA0E;AAC1E,4EAA4E;AAC5E,6EAA6E;AAC7E,8EAA8E;AAC9E,iFAAiF;AAmCjF,MAAM,YAAY,GAAe,MAAM,CAAC,MAAM,CAAC;IAC7C,UAAU,EAAE,eAAe;IAC3B,mBAAmB,EAAE,UAAU;IAC/B,mBAAmB,EAAE,UAAU;IAC/B,mBAAmB,EAAE,MAAM;CAC5B,CAAC,CAAC;AAEH,MAAM,eAAe,GAAe,MAAM,CAAC,MAAM,CAAC;IAChD,UAAU,EAAE,cAAc;IAC1B,mBAAmB,EAAE,OAAO;IAC5B,mBAAmB,EAAE,OAAO;IAC5B,mBAAmB,EAAE,uBAAuB;CAC7C,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAkB;IAC9C,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,OAAO;YACV,OAAO,YAAY,CAAC;QACtB,KAAK,UAAU;YACb,OAAO,eAAe,CAAC;QACzB,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,WAAW,GAAU,IAAI,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,uDAAuD,MAAM,CAAC,WAAW,CAAC,GAAG,CAC9E,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
import { getRulePolicy } from './rule-policy.js';
|
|
3
3
|
describe('getRulePolicy (ADR-112 §9 single-home)', () => {
|
|
4
|
-
it('mined → held-out-only label scope + held-out controls (the LIVE, byte-identical path)', () => {
|
|
4
|
+
it('mined → held-out-only label scope + held-out controls + no positive-control gate (the LIVE, byte-identical path)', () => {
|
|
5
5
|
expect(getRulePolicy('mined')).toEqual({
|
|
6
6
|
labelScope: 'held-out-only',
|
|
7
7
|
positiveControlSide: 'held-out',
|
|
8
8
|
exposureControlSide: 'held-out',
|
|
9
|
+
positiveControlGate: 'none',
|
|
9
10
|
});
|
|
10
11
|
});
|
|
11
|
-
it('authored → whole-window labels + train-side controls (DEFINED for slice D
|
|
12
|
+
it('authored → whole-window labels + train-side controls + preimage-differential gate (DEFINED for slice C2b/D)', () => {
|
|
12
13
|
expect(getRulePolicy('authored')).toEqual({
|
|
13
14
|
labelScope: 'whole-window',
|
|
14
15
|
positiveControlSide: 'train',
|
|
15
16
|
exposureControlSide: 'train',
|
|
17
|
+
positiveControlGate: 'preimage-differential',
|
|
16
18
|
});
|
|
17
19
|
});
|
|
18
20
|
it('mined and authored diverge on label scope (the §9 amendment the scorer reads in slice D)', () => {
|
|
19
21
|
expect(getRulePolicy('mined').labelScope).not.toBe(getRulePolicy('authored').labelScope);
|
|
20
22
|
});
|
|
23
|
+
it('mined and authored diverge on the positive-control gate (§4 — authored is differential-gated)', () => {
|
|
24
|
+
expect(getRulePolicy('mined').positiveControlGate).toBe('none');
|
|
25
|
+
expect(getRulePolicy('authored').positiveControlGate).toBe('preimage-differential');
|
|
26
|
+
});
|
|
21
27
|
it('returns a frozen singleton — a caller cannot mutate policy resolution process-wide (#2259)', () => {
|
|
22
28
|
const policy = getRulePolicy('mined');
|
|
23
29
|
// Frozen ⇒ any property write throws in strict mode (ESM), so policy resolution can't be
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-policy.test.js","sourceRoot":"","sources":["../../src/spine/rule-policy.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACtD,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"rule-policy.test.js","sourceRoot":"","sources":["../../src/spine/rule-policy.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACtD,EAAE,CAAC,kHAAkH,EAAE,GAAG,EAAE;QAC1H,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;YACrC,UAAU,EAAE,eAAe;YAC3B,mBAAmB,EAAE,UAAU;YAC/B,mBAAmB,EAAE,UAAU;YAC/B,mBAAmB,EAAE,MAAM;SAC5B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6GAA6G,EAAE,GAAG,EAAE;QACrH,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;YACxC,UAAU,EAAE,cAAc;YAC1B,mBAAmB,EAAE,OAAO;YAC5B,mBAAmB,EAAE,OAAO;YAC5B,mBAAmB,EAAE,uBAAuB;SAC7C,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0FAA0F,EAAE,GAAG,EAAE;QAClG,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC;IAC3F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+FAA+F,EAAE,GAAG,EAAE;QACvG,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChE,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4FAA4F,EAAE,GAAG,EAAE;QACpG,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QACtC,yFAAyF;QACzF,6FAA6F;QAC7F,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QAC9E,+DAA+D;QAC/D,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|