@principles/core 1.161.0 → 1.163.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/runtime-v2/__tests__/adversarial-loop.test.js +24 -78
- package/dist/runtime-v2/__tests__/adversarial-loop.test.js.map +1 -1
- package/dist/runtime-v2/__tests__/architecture-regression.test.js +9 -5
- package/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
- package/dist/runtime-v2/__tests__/artificer-runner-vslice.test.js +32 -80
- package/dist/runtime-v2/__tests__/artificer-runner-vslice.test.js.map +1 -1
- package/dist/runtime-v2/__tests__/full-chain-real-llm.test.js +2 -2
- package/dist/runtime-v2/__tests__/full-chain-real-llm.test.js.map +1 -1
- package/dist/runtime-v2/__tests__/principle-compiler-core.test.js +7 -7
- package/dist/runtime-v2/__tests__/principle-compiler-core.test.js.map +1 -1
- package/dist/runtime-v2/activation/__tests__/production-gate-deps.test.js +24 -1
- package/dist/runtime-v2/activation/__tests__/production-gate-deps.test.js.map +1 -1
- package/dist/runtime-v2/activation/production-gate-deps.d.ts.map +1 -1
- package/dist/runtime-v2/activation/production-gate-deps.js +18 -1
- package/dist/runtime-v2/activation/production-gate-deps.js.map +1 -1
- package/dist/runtime-v2/adapter/__tests__/artificer-l2-adapter.test.js +277 -475
- package/dist/runtime-v2/adapter/__tests__/artificer-l2-adapter.test.js.map +1 -1
- package/dist/runtime-v2/adapter/artificer-l2-adapter.d.ts +14 -34
- package/dist/runtime-v2/adapter/artificer-l2-adapter.d.ts.map +1 -1
- package/dist/runtime-v2/adapter/artificer-l2-adapter.js +182 -222
- package/dist/runtime-v2/adapter/artificer-l2-adapter.js.map +1 -1
- package/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js +2 -2
- package/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js.map +1 -1
- package/dist/runtime-v2/adversarial-loop.d.ts.map +1 -1
- package/dist/runtime-v2/adversarial-loop.js +5 -27
- package/dist/runtime-v2/adversarial-loop.js.map +1 -1
- package/dist/runtime-v2/golden-trace-replay-validator.d.ts +8 -0
- package/dist/runtime-v2/golden-trace-replay-validator.d.ts.map +1 -1
- package/dist/runtime-v2/golden-trace-replay-validator.js +3 -3
- package/dist/runtime-v2/golden-trace-replay-validator.js.map +1 -1
- package/dist/runtime-v2/golden-trace.d.ts +16 -1
- package/dist/runtime-v2/golden-trace.d.ts.map +1 -1
- package/dist/runtime-v2/golden-trace.js +13 -4
- package/dist/runtime-v2/golden-trace.js.map +1 -1
- package/dist/runtime-v2/index.d.ts +8 -5
- package/dist/runtime-v2/index.d.ts.map +1 -1
- package/dist/runtime-v2/index.js +11 -4
- package/dist/runtime-v2/index.js.map +1 -1
- package/dist/runtime-v2/internalization/__tests__/artificer-prompt-builder.test.js +3 -2
- package/dist/runtime-v2/internalization/__tests__/artificer-prompt-builder.test.js.map +1 -1
- package/dist/runtime-v2/internalization/__tests__/artificer-rule-output.test.d.ts +2 -0
- package/dist/runtime-v2/internalization/__tests__/artificer-rule-output.test.d.ts.map +1 -0
- package/dist/runtime-v2/internalization/__tests__/{artificer-output-v2.test.js → artificer-rule-output.test.js} +126 -127
- package/dist/runtime-v2/internalization/__tests__/artificer-rule-output.test.js.map +1 -0
- package/dist/runtime-v2/internalization/__tests__/rule-code-dialect.test.d.ts +2 -0
- package/dist/runtime-v2/internalization/__tests__/rule-code-dialect.test.d.ts.map +1 -0
- package/dist/runtime-v2/internalization/__tests__/rule-code-dialect.test.js +270 -0
- package/dist/runtime-v2/internalization/__tests__/rule-code-dialect.test.js.map +1 -0
- package/dist/runtime-v2/internalization/__tests__/rule-host-input-builder.test.d.ts +2 -0
- package/dist/runtime-v2/internalization/__tests__/rule-host-input-builder.test.d.ts.map +1 -0
- package/dist/runtime-v2/internalization/__tests__/rule-host-input-builder.test.js +180 -0
- package/dist/runtime-v2/internalization/__tests__/rule-host-input-builder.test.js.map +1 -0
- package/dist/runtime-v2/internalization/artificer-output.d.ts +33 -51
- package/dist/runtime-v2/internalization/artificer-output.d.ts.map +1 -1
- package/dist/runtime-v2/internalization/artificer-output.js +48 -87
- package/dist/runtime-v2/internalization/artificer-output.js.map +1 -1
- package/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts +1 -1
- package/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts.map +1 -1
- package/dist/runtime-v2/internalization/artificer-prompt-builder.js +5 -17
- package/dist/runtime-v2/internalization/artificer-prompt-builder.js.map +1 -1
- package/dist/runtime-v2/internalization/artificer-runner.d.ts +8 -8
- package/dist/runtime-v2/internalization/artificer-runner.d.ts.map +1 -1
- package/dist/runtime-v2/internalization/artificer-runner.js +5 -5
- package/dist/runtime-v2/internalization/artificer-runner.js.map +1 -1
- package/dist/runtime-v2/internalization/evaluator-runner.d.ts +1 -1
- package/dist/runtime-v2/internalization/evaluator-runner.js +2 -2
- package/dist/runtime-v2/internalization/index.d.ts +9 -4
- package/dist/runtime-v2/internalization/index.d.ts.map +1 -1
- package/dist/runtime-v2/internalization/index.js +8 -3
- package/dist/runtime-v2/internalization/index.js.map +1 -1
- package/dist/runtime-v2/internalization/rule-code-validator.d.ts +16 -0
- package/dist/runtime-v2/internalization/rule-code-validator.d.ts.map +1 -1
- package/dist/runtime-v2/internalization/rule-code-validator.js +50 -1
- package/dist/runtime-v2/internalization/rule-code-validator.js.map +1 -1
- package/dist/runtime-v2/internalization/rule-host-input-builder.d.ts +62 -0
- package/dist/runtime-v2/internalization/rule-host-input-builder.d.ts.map +1 -0
- package/dist/runtime-v2/internalization/rule-host-input-builder.js +182 -0
- package/dist/runtime-v2/internalization/rule-host-input-builder.js.map +1 -0
- package/dist/runtime-v2/internalization/rule-host-validator.d.ts.map +1 -1
- package/dist/runtime-v2/internalization/rule-host-validator.js +22 -1
- package/dist/runtime-v2/internalization/rule-host-validator.js.map +1 -1
- package/dist/runtime-v2/internalization/template-generator.d.ts +7 -2
- package/dist/runtime-v2/internalization/template-generator.d.ts.map +1 -1
- package/dist/runtime-v2/internalization/template-generator.js +10 -5
- package/dist/runtime-v2/internalization/template-generator.js.map +1 -1
- package/dist/runtime-v2/tools/__tests__/artificer-l2-tool-contract.test.d.ts +2 -0
- package/dist/runtime-v2/tools/__tests__/artificer-l2-tool-contract.test.d.ts.map +1 -0
- package/dist/runtime-v2/tools/__tests__/artificer-l2-tool-contract.test.js +322 -0
- package/dist/runtime-v2/tools/__tests__/artificer-l2-tool-contract.test.js.map +1 -0
- package/dist/runtime-v2/tools/__tests__/artificer-output-typebox.test.d.ts +2 -0
- package/dist/runtime-v2/tools/__tests__/artificer-output-typebox.test.d.ts.map +1 -0
- package/dist/runtime-v2/tools/__tests__/artificer-output-typebox.test.js +149 -0
- package/dist/runtime-v2/tools/__tests__/artificer-output-typebox.test.js.map +1 -0
- package/dist/runtime-v2/tools/artificer-l2-tool-contract.d.ts +72 -0
- package/dist/runtime-v2/tools/artificer-l2-tool-contract.d.ts.map +1 -0
- package/dist/runtime-v2/tools/artificer-l2-tool-contract.js +275 -0
- package/dist/runtime-v2/tools/artificer-l2-tool-contract.js.map +1 -0
- package/dist/runtime-v2/tools/artificer-output-typebox.d.ts +78 -0
- package/dist/runtime-v2/tools/artificer-output-typebox.d.ts.map +1 -0
- package/dist/runtime-v2/tools/artificer-output-typebox.js +70 -0
- package/dist/runtime-v2/tools/artificer-output-typebox.js.map +1 -0
- package/dist/telemetry-event.d.ts +2 -2
- package/dist/telemetry-event.d.ts.map +1 -1
- package/dist/telemetry-event.js +5 -3
- package/dist/telemetry-event.js.map +1 -1
- package/package.json +1 -1
- package/dist/runtime-v2/internalization/__tests__/artificer-output-v2.test.d.ts +0 -2
- package/dist/runtime-v2/internalization/__tests__/artificer-output-v2.test.d.ts.map +0 -1
- package/dist/runtime-v2/internalization/__tests__/artificer-output-v2.test.js.map +0 -1
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRI-439 Phase 2: RuleCode dialect contract — TDD tests
|
|
3
|
+
*
|
|
4
|
+
* Canonical dialect: synchronous bare `function evaluate(input, helpers)`.
|
|
5
|
+
* Strict forbidden patterns: export, import, async, eval, Function, I/O,
|
|
6
|
+
* network, timers, random.
|
|
7
|
+
* Decision: exactly 4 values (allow | block | requireApproval | auto_correct).
|
|
8
|
+
* matched=false → decision must be 'allow'.
|
|
9
|
+
* auto_correct → correctionProposal required (already enforced, smoke-tested here).
|
|
10
|
+
*/
|
|
11
|
+
import { describe, it, expect } from 'vitest';
|
|
12
|
+
// ── New forbidden patterns (PRI-439 Phase 2) ────────────────────────────────
|
|
13
|
+
describe('PRI-439 Phase 2: new forbidden patterns', () => {
|
|
14
|
+
async function getModule() {
|
|
15
|
+
return import('../rule-code-validator.js');
|
|
16
|
+
}
|
|
17
|
+
// ── export (canonical is bare function, no ESM export) ──────────────────
|
|
18
|
+
it('rejects `export function evaluate`', async () => {
|
|
19
|
+
const { checkForbiddenPatterns } = await getModule();
|
|
20
|
+
const labels = checkForbiddenPatterns(`export function evaluate(input, helpers) {\n return { decision: 'allow', matched: false, reason: 'x' };\n}`);
|
|
21
|
+
expect(labels).toContain('export');
|
|
22
|
+
});
|
|
23
|
+
it('rejects `export const meta`', async () => {
|
|
24
|
+
const { checkForbiddenPatterns } = await getModule();
|
|
25
|
+
const labels = checkForbiddenPatterns(`export const meta = { name: 'x' };\nfunction evaluate(input, helpers) { return { decision: 'allow', matched: false, reason: 'x' }; }`);
|
|
26
|
+
expect(labels).toContain('export');
|
|
27
|
+
});
|
|
28
|
+
it('accepts bare `function evaluate(input, helpers)` (canonical form)', async () => {
|
|
29
|
+
const { checkForbiddenPatterns } = await getModule();
|
|
30
|
+
const labels = checkForbiddenPatterns(`const meta = { name: 'x' };\nfunction evaluate(input, helpers) {\n return { decision: 'allow', matched: false, reason: 'x' };\n}`);
|
|
31
|
+
expect(labels).not.toContain('export');
|
|
32
|
+
});
|
|
33
|
+
// ── async / await (canonical is synchronous) ────────────────────────────
|
|
34
|
+
it('rejects `async function evaluate`', async () => {
|
|
35
|
+
const { checkForbiddenPatterns } = await getModule();
|
|
36
|
+
const labels = checkForbiddenPatterns(`async function evaluate(input, helpers) {\n return { decision: 'allow', matched: false, reason: 'x' };\n}`);
|
|
37
|
+
expect(labels).toContain('async');
|
|
38
|
+
});
|
|
39
|
+
it('rejects `await` inside evaluate', async () => {
|
|
40
|
+
const { checkForbiddenPatterns } = await getModule();
|
|
41
|
+
const labels = checkForbiddenPatterns(`function evaluate(input, helpers) {\n const x = await fetch('/x');\n return { decision: 'allow', matched: false, reason: 'x' };\n}`);
|
|
42
|
+
expect(labels).toContain('await');
|
|
43
|
+
});
|
|
44
|
+
it('does not false-positive on `async` in a string literal', async () => {
|
|
45
|
+
const { checkForbiddenPatterns } = await getModule();
|
|
46
|
+
// `async` inside a string should not be flagged by the word-boundary regex.
|
|
47
|
+
// NOTE: This is a best-effort static check. If the regex is too broad it
|
|
48
|
+
// will false-positive on legitimate reason strings mentioning "async".
|
|
49
|
+
// We assert the canonical clean code passes.
|
|
50
|
+
const labels = checkForbiddenPatterns(`function evaluate(input, helpers) {\n return { decision: 'allow', matched: false, reason: 'synchronous not async' };\n}`);
|
|
51
|
+
// The word-boundary regex \basync\b WILL match "async" inside the string.
|
|
52
|
+
// This is a known limitation of regex-based static analysis. We document
|
|
53
|
+
// it here: the check is conservative (false positives on string literals
|
|
54
|
+
// are acceptable; false negatives are not).
|
|
55
|
+
// If this becomes a problem in practice, migrate to an AST-based check.
|
|
56
|
+
if (labels.includes('async')) {
|
|
57
|
+
// Conservative match inside string — acceptable for now.
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
expect(labels).not.toContain('async');
|
|
61
|
+
});
|
|
62
|
+
// ── Math.random (non-deterministic randomness) ──────────────────────────
|
|
63
|
+
it('rejects Math.random()', async () => {
|
|
64
|
+
const { checkForbiddenPatterns } = await getModule();
|
|
65
|
+
const labels = checkForbiddenPatterns(`function evaluate(input, helpers) {\n if (Math.random() > 0.5) { return { decision: 'block', matched: true, reason: 'x' }; }\n return { decision: 'allow', matched: false, reason: 'x' };\n}`);
|
|
66
|
+
expect(labels).toContain('Math.random');
|
|
67
|
+
});
|
|
68
|
+
// ── Timers: setImmediate, queueMicrotask (extends setTimeout/setInterval) ─
|
|
69
|
+
it('rejects setImmediate', async () => {
|
|
70
|
+
const { checkForbiddenPatterns } = await getModule();
|
|
71
|
+
const labels = checkForbiddenPatterns(`function evaluate(input, helpers) {\n setImmediate(() => {});\n return { decision: 'allow', matched: false, reason: 'x' };\n}`);
|
|
72
|
+
expect(labels).toContain('setImmediate');
|
|
73
|
+
});
|
|
74
|
+
it('rejects queueMicrotask', async () => {
|
|
75
|
+
const { checkForbiddenPatterns } = await getModule();
|
|
76
|
+
const labels = checkForbiddenPatterns(`function evaluate(input, helpers) {\n queueMicrotask(() => {});\n return { decision: 'allow', matched: false, reason: 'x' };\n}`);
|
|
77
|
+
expect(labels).toContain('queueMicrotask');
|
|
78
|
+
});
|
|
79
|
+
// ── Network: XMLHttpRequest ──────────────────────────────────────────────
|
|
80
|
+
it('rejects XMLHttpRequest', async () => {
|
|
81
|
+
const { checkForbiddenPatterns } = await getModule();
|
|
82
|
+
const labels = checkForbiddenPatterns(`function evaluate(input, helpers) {\n const xhr = new XMLHttpRequest();\n return { decision: 'allow', matched: false, reason: 'x' };\n}`);
|
|
83
|
+
expect(labels).toContain('XMLHttpRequest');
|
|
84
|
+
});
|
|
85
|
+
// ── crypto (non-deterministic / side-channel) ────────────────────────────
|
|
86
|
+
it('rejects crypto.randomBytes', async () => {
|
|
87
|
+
const { checkForbiddenPatterns } = await getModule();
|
|
88
|
+
const labels = checkForbiddenPatterns(`function evaluate(input, helpers) {\n const x = crypto.randomBytes(4);\n return { decision: 'allow', matched: false, reason: 'x' };\n}`);
|
|
89
|
+
expect(labels).toContain('crypto');
|
|
90
|
+
});
|
|
91
|
+
// ── Bracket access to new forbidden globals ──────────────────────────────
|
|
92
|
+
it('rejects bracket access to setImmediate', async () => {
|
|
93
|
+
const { checkForbiddenPatterns } = await getModule();
|
|
94
|
+
const labels = checkForbiddenPatterns(`function evaluate(input, helpers) {\n const fn = globalThis['setImmediate'];\n return { decision: 'allow', matched: false, reason: 'x' };\n}`);
|
|
95
|
+
// globalThis is already forbidden, but bracket-access to setImmediate
|
|
96
|
+
// should also be caught.
|
|
97
|
+
expect(labels).toContain('bracket access to forbidden global');
|
|
98
|
+
});
|
|
99
|
+
// ── Canonical clean code passes ──────────────────────────────────────────
|
|
100
|
+
it('canonical bare function evaluate(input, helpers) passes with zero violations', async () => {
|
|
101
|
+
const { checkForbiddenPatterns } = await getModule();
|
|
102
|
+
const code = [
|
|
103
|
+
`const meta = { name: 'R1', version: '1.0.0', ruleId: 'R1', coversCondition: 'test' };`,
|
|
104
|
+
`function evaluate(input, helpers) {`,
|
|
105
|
+
` if (input.action.toolName === 'write' && helpers.isRiskPath()) {`,
|
|
106
|
+
` return { decision: 'block', matched: true, reason: 'risk path' };`,
|
|
107
|
+
` }`,
|
|
108
|
+
` return { decision: 'allow', matched: false, reason: 'safe' };`,
|
|
109
|
+
`}`,
|
|
110
|
+
].join('\n');
|
|
111
|
+
expect(checkForbiddenPatterns(code)).toEqual([]);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
// ── matched=false → decision must be 'allow' (PRI-439 Phase 2) ──────────────
|
|
115
|
+
describe('PRI-439 Phase 2: matched=false decision constraint', () => {
|
|
116
|
+
async function getValidator() {
|
|
117
|
+
return import('../rule-host-validator.js');
|
|
118
|
+
}
|
|
119
|
+
async function getCodeValidator() {
|
|
120
|
+
return import('../rule-code-validator.js');
|
|
121
|
+
}
|
|
122
|
+
// ── Runtime validation (validateRuleHostResult) ──────────────────────────
|
|
123
|
+
it('runtime: matched=false with decision=allow is valid', async () => {
|
|
124
|
+
const { validateRuleHostResult } = await getValidator();
|
|
125
|
+
const result = validateRuleHostResult({
|
|
126
|
+
decision: 'allow',
|
|
127
|
+
matched: false,
|
|
128
|
+
reason: 'rule not applicable',
|
|
129
|
+
});
|
|
130
|
+
expect(result.valid).toBe(true);
|
|
131
|
+
});
|
|
132
|
+
it('runtime: matched=false with decision=block is INVALID', async () => {
|
|
133
|
+
const { validateRuleHostResult } = await getValidator();
|
|
134
|
+
const result = validateRuleHostResult({
|
|
135
|
+
decision: 'block',
|
|
136
|
+
matched: false,
|
|
137
|
+
reason: 'contradictory',
|
|
138
|
+
});
|
|
139
|
+
expect(result.valid).toBe(false);
|
|
140
|
+
expect(result.errors.join(' ')).toMatch(/matched.*false.*allow|allow.*matched.*false/i);
|
|
141
|
+
});
|
|
142
|
+
it('runtime: matched=false with decision=requireApproval is INVALID', async () => {
|
|
143
|
+
const { validateRuleHostResult } = await getValidator();
|
|
144
|
+
const result = validateRuleHostResult({
|
|
145
|
+
decision: 'requireApproval',
|
|
146
|
+
matched: false,
|
|
147
|
+
reason: 'contradictory',
|
|
148
|
+
});
|
|
149
|
+
expect(result.valid).toBe(false);
|
|
150
|
+
});
|
|
151
|
+
it('runtime: matched=false with decision=auto_correct is INVALID', async () => {
|
|
152
|
+
const { validateRuleHostResult } = await getValidator();
|
|
153
|
+
const result = validateRuleHostResult({
|
|
154
|
+
decision: 'auto_correct',
|
|
155
|
+
matched: false,
|
|
156
|
+
reason: 'contradictory',
|
|
157
|
+
correctionProposal: {
|
|
158
|
+
ruleId: 'R1',
|
|
159
|
+
correctedFields: { command: 'safe' },
|
|
160
|
+
proposedParams: { command: 'safe' },
|
|
161
|
+
applicationMode: 'replace_params',
|
|
162
|
+
confidence: 0.9,
|
|
163
|
+
notifyAgent: true,
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
expect(result.valid).toBe(false);
|
|
167
|
+
});
|
|
168
|
+
it('runtime: matched=true with decision=block is valid (no constraint)', async () => {
|
|
169
|
+
const { validateRuleHostResult } = await getValidator();
|
|
170
|
+
const result = validateRuleHostResult({
|
|
171
|
+
decision: 'block',
|
|
172
|
+
matched: true,
|
|
173
|
+
reason: 'blocked',
|
|
174
|
+
});
|
|
175
|
+
expect(result.valid).toBe(true);
|
|
176
|
+
});
|
|
177
|
+
// ── Static check (checkMatchedFalseDecisions) ────────────────────────────
|
|
178
|
+
it('static: flags return { matched: false, decision: "block" }', async () => {
|
|
179
|
+
const { checkMatchedFalseDecisions } = await getCodeValidator();
|
|
180
|
+
const code = `function evaluate(input, helpers) {
|
|
181
|
+
return { decision: 'block', matched: false, reason: 'x' };
|
|
182
|
+
}`;
|
|
183
|
+
const violations = checkMatchedFalseDecisions(code);
|
|
184
|
+
expect(violations.length).toBeGreaterThanOrEqual(1);
|
|
185
|
+
expect(violations[0]).toMatch(/matched.*false.*allow/i);
|
|
186
|
+
});
|
|
187
|
+
it('static: does NOT flag return { matched: false, decision: "allow" }', async () => {
|
|
188
|
+
const { checkMatchedFalseDecisions } = await getCodeValidator();
|
|
189
|
+
const code = `function evaluate(input, helpers) {
|
|
190
|
+
return { decision: 'allow', matched: false, reason: 'safe' };
|
|
191
|
+
}`;
|
|
192
|
+
const violations = checkMatchedFalseDecisions(code);
|
|
193
|
+
expect(violations).toEqual([]);
|
|
194
|
+
});
|
|
195
|
+
it('static: does NOT flag return { matched: true, decision: "block" }', async () => {
|
|
196
|
+
const { checkMatchedFalseDecisions } = await getCodeValidator();
|
|
197
|
+
const code = `function evaluate(input, helpers) {
|
|
198
|
+
return { decision: 'block', matched: true, reason: 'blocked' };
|
|
199
|
+
}`;
|
|
200
|
+
const violations = checkMatchedFalseDecisions(code);
|
|
201
|
+
expect(violations).toEqual([]);
|
|
202
|
+
});
|
|
203
|
+
it('static: does NOT flag complex returns with nested braces', async () => {
|
|
204
|
+
const { checkMatchedFalseDecisions } = await getCodeValidator();
|
|
205
|
+
const code = `function evaluate(input, helpers) {
|
|
206
|
+
return { decision: 'auto_correct', matched: true, reason: 'fix', correctionProposal: { params: { a: 1 } } };
|
|
207
|
+
}`;
|
|
208
|
+
const violations = checkMatchedFalseDecisions(code);
|
|
209
|
+
expect(violations).toEqual([]);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
// ── Template generator emits canonical bare form (PRI-439 Phase 2) ──────────
|
|
213
|
+
describe('PRI-439 Phase 2: template generator canonical form', () => {
|
|
214
|
+
async function getModule() {
|
|
215
|
+
return import('../template-generator.js');
|
|
216
|
+
}
|
|
217
|
+
it('emits bare `function evaluate(input, helpers)` (no export keyword)', async () => {
|
|
218
|
+
const { generateFromTemplate } = await getModule();
|
|
219
|
+
const result = generateFromTemplate('P_TEST', 'test', [{ toolName: 'bash' }]);
|
|
220
|
+
expect(result).not.toBeNull();
|
|
221
|
+
expect(result).toContain('function evaluate(input, helpers)');
|
|
222
|
+
expect(result).not.toContain('export function evaluate');
|
|
223
|
+
});
|
|
224
|
+
it('emits bare `const meta` (no export keyword)', async () => {
|
|
225
|
+
const { generateFromTemplate } = await getModule();
|
|
226
|
+
const result = generateFromTemplate('P_TEST', 'test', [{ toolName: 'bash' }]);
|
|
227
|
+
expect(result).not.toBeNull();
|
|
228
|
+
expect(result).toContain('const meta =');
|
|
229
|
+
expect(result).not.toContain('export const meta');
|
|
230
|
+
});
|
|
231
|
+
it('default return includes decision: "allow" and reason', async () => {
|
|
232
|
+
const { generateFromTemplate } = await getModule();
|
|
233
|
+
const result = generateFromTemplate('P_TEST', 'test', [{ toolName: 'bash' }]);
|
|
234
|
+
expect(result).not.toBeNull();
|
|
235
|
+
expect(result).toMatch(/return\s*\{\s*decision:\s*['"]allow['"]/);
|
|
236
|
+
expect(result).toMatch(/matched:\s*false/);
|
|
237
|
+
expect(result).toMatch(/reason:\s*'/);
|
|
238
|
+
});
|
|
239
|
+
it('generated code passes checkForbiddenPatterns', async () => {
|
|
240
|
+
const { generateFromTemplate } = await getModule();
|
|
241
|
+
const { checkForbiddenPatterns } = await import('../rule-code-validator.js');
|
|
242
|
+
const result = generateFromTemplate('P_TEST', 'test', [{ toolName: 'bash', commandRegex: 'rm' }]);
|
|
243
|
+
expect(result).not.toBeNull();
|
|
244
|
+
if (result === null)
|
|
245
|
+
throw new Error('expected non-null result');
|
|
246
|
+
const labels = checkForbiddenPatterns(result);
|
|
247
|
+
expect(labels).toEqual([]);
|
|
248
|
+
});
|
|
249
|
+
it('generated code passes checkReturnStatementsMissingFields', async () => {
|
|
250
|
+
const { generateFromTemplate } = await getModule();
|
|
251
|
+
const { checkReturnStatementsMissingFields } = await import('../rule-code-validator.js');
|
|
252
|
+
const result = generateFromTemplate('P_TEST', 'test', [{ toolName: 'bash', commandRegex: 'rm' }]);
|
|
253
|
+
expect(result).not.toBeNull();
|
|
254
|
+
if (result === null)
|
|
255
|
+
throw new Error('expected non-null result');
|
|
256
|
+
const violations = checkReturnStatementsMissingFields(result);
|
|
257
|
+
expect(violations).toEqual([]);
|
|
258
|
+
});
|
|
259
|
+
it('generated code passes checkMatchedFalseDecisions', async () => {
|
|
260
|
+
const { generateFromTemplate } = await getModule();
|
|
261
|
+
const { checkMatchedFalseDecisions } = await import('../rule-code-validator.js');
|
|
262
|
+
const result = generateFromTemplate('P_TEST', 'test', [{ toolName: 'bash', commandRegex: 'rm' }]);
|
|
263
|
+
expect(result).not.toBeNull();
|
|
264
|
+
if (result === null)
|
|
265
|
+
throw new Error('expected non-null result');
|
|
266
|
+
const violations = checkMatchedFalseDecisions(result);
|
|
267
|
+
expect(violations).toEqual([]);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
//# sourceMappingURL=rule-code-dialect.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-code-dialect.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/internalization/__tests__/rule-code-dialect.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE9C,+EAA+E;AAE/E,QAAQ,CAAC,yCAAyC,EAAE,GAAG,EAAE;IACvD,KAAK,UAAU,SAAS;QACtB,OAAO,MAAM,CAAC,2BAA2B,CAAC,CAAC;IAC7C,CAAC;IAED,2EAA2E;IAE3E,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,sBAAsB,CACnC,6GAA6G,CAC9G,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,sBAAsB,CACnC,sIAAsI,CACvI,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,sBAAsB,CACnC,mIAAmI,CACpI,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,2EAA2E;IAE3E,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,sBAAsB,CACnC,4GAA4G,CAC7G,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,sBAAsB,CACnC,sIAAsI,CACvI,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACrD,4EAA4E;QAC5E,yEAAyE;QACzE,uEAAuE;QACvE,6CAA6C;QAC7C,MAAM,MAAM,GAAG,sBAAsB,CACnC,0HAA0H,CAC3H,CAAC;QACF,0EAA0E;QAC1E,yEAAyE;QACzE,yEAAyE;QACzE,4CAA4C;QAC5C,wEAAwE;QACxE,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,yDAAyD;YACzD,OAAO;QACT,CAAC;QACD,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,2EAA2E;IAE3E,EAAE,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;QACrC,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,sBAAsB,CACnC,gMAAgM,CACjM,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAE7E,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,sBAAsB,CACnC,iIAAiI,CAClI,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;QACtC,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,sBAAsB,CACnC,mIAAmI,CACpI,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,4EAA4E;IAE5E,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;QACtC,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,sBAAsB,CACnC,2IAA2I,CAC5I,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,4EAA4E;IAE5E,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,sBAAsB,CACnC,0IAA0I,CAC3I,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,4EAA4E;IAE5E,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,sBAAsB,CACnC,gJAAgJ,CACjJ,CAAC;QACF,sEAAsE;QACtE,yBAAyB;QACzB,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,oCAAoC,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,4EAA4E;IAE5E,EAAE,CAAC,8EAA8E,EAAE,KAAK,IAAI,EAAE;QAC5F,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG;YACX,uFAAuF;YACvF,qCAAqC;YACrC,oEAAoE;YACpE,uEAAuE;YACvE,KAAK;YACL,iEAAiE;YACjE,GAAG;SACJ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACb,MAAM,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,+EAA+E;AAE/E,QAAQ,CAAC,oDAAoD,EAAE,GAAG,EAAE;IAClE,KAAK,UAAU,YAAY;QACzB,OAAO,MAAM,CAAC,2BAA2B,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,UAAU,gBAAgB;QAC7B,OAAO,MAAM,CAAC,2BAA2B,CAAC,CAAC;IAC7C,CAAC;IAED,4EAA4E;IAE5E,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;QACxD,MAAM,MAAM,GAAG,sBAAsB,CAAC;YACpC,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,qBAAqB;SAC9B,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;QACxD,MAAM,MAAM,GAAG,sBAAsB,CAAC;YACpC,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,eAAe;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,8CAA8C,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;QACxD,MAAM,MAAM,GAAG,sBAAsB,CAAC;YACpC,QAAQ,EAAE,iBAAiB;YAC3B,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,eAAe;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;QACxD,MAAM,MAAM,GAAG,sBAAsB,CAAC;YACpC,QAAQ,EAAE,cAAc;YACxB,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,eAAe;YACvB,kBAAkB,EAAE;gBAClB,MAAM,EAAE,IAAI;gBACZ,eAAe,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;gBACpC,cAAc,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;gBACnC,eAAe,EAAE,gBAAgB;gBACjC,UAAU,EAAE,GAAG;gBACf,WAAW,EAAE,IAAI;aAClB;SACF,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;QAClF,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;QACxD,MAAM,MAAM,GAAG,sBAAsB,CAAC;YACpC,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,SAAS;SAClB,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,4EAA4E;IAE5E,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,MAAM,EAAE,0BAA0B,EAAE,GAAG,MAAM,gBAAgB,EAAE,CAAC;QAChE,MAAM,IAAI,GAAG;;EAEf,CAAC;QACC,MAAM,UAAU,GAAG,0BAA0B,CAAC,IAAI,CAAC,CAAC;QACpD,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;QAClF,MAAM,EAAE,0BAA0B,EAAE,GAAG,MAAM,gBAAgB,EAAE,CAAC;QAChE,MAAM,IAAI,GAAG;;EAEf,CAAC;QACC,MAAM,UAAU,GAAG,0BAA0B,CAAC,IAAI,CAAC,CAAC;QACpD,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,EAAE,0BAA0B,EAAE,GAAG,MAAM,gBAAgB,EAAE,CAAC;QAChE,MAAM,IAAI,GAAG;;EAEf,CAAC;QACC,MAAM,UAAU,GAAG,0BAA0B,CAAC,IAAI,CAAC,CAAC;QACpD,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,EAAE,0BAA0B,EAAE,GAAG,MAAM,gBAAgB,EAAE,CAAC;QAChE,MAAM,IAAI,GAAG;;EAEf,CAAC;QACC,MAAM,UAAU,GAAG,0BAA0B,CAAC,IAAI,CAAC,CAAC;QACpD,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,+EAA+E;AAE/E,QAAQ,CAAC,oDAAoD,EAAE,GAAG,EAAE;IAClE,KAAK,UAAU,SAAS;QACtB,OAAO,MAAM,CAAC,0BAA0B,CAAC,CAAC;IAC5C,CAAC;IAED,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;QAClF,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAC9E,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,mCAAmC,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAC9E,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAC9E,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,yCAAyC,CAAC,CAAC;QAClE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACnD,MAAM,EAAE,sBAAsB,EAAE,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;QAC7E,MAAM,MAAM,GAAG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAClG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,IAAI,MAAM,KAAK,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACjE,MAAM,MAAM,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACnD,MAAM,EAAE,kCAAkC,EAAE,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;QACzF,MAAM,MAAM,GAAG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAClG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,IAAI,MAAM,KAAK,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACjE,MAAM,UAAU,GAAG,kCAAkC,CAAC,MAAM,CAAC,CAAC;QAC9D,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,SAAS,EAAE,CAAC;QACnD,MAAM,EAAE,0BAA0B,EAAE,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;QACjF,MAAM,MAAM,GAAG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAClG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,IAAI,MAAM,KAAK,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACjE,MAAM,UAAU,GAAG,0BAA0B,CAAC,MAAM,CAAC,CAAC;QACtD,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-host-input-builder.test.d.ts","sourceRoot":"","sources":["../../../../src/runtime-v2/internalization/__tests__/rule-host-input-builder.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRI-439 Phase 3: Unified production input — pure normalizePath + action builder
|
|
3
|
+
*
|
|
4
|
+
* Golden Trace and OpenClaw Gate must produce the SAME `normalizedPath` for
|
|
5
|
+
* 6 path types. This file tests the pure extraction + normalization logic
|
|
6
|
+
* that both paths must share.
|
|
7
|
+
*
|
|
8
|
+
* 6 path types:
|
|
9
|
+
* 1. Absolute POSIX (/project/src/index.ts, /project)
|
|
10
|
+
* 2. Absolute Windows (D:\project\src\index.ts, D:\project)
|
|
11
|
+
* 3. Relative bare (src/index.ts, /project)
|
|
12
|
+
* 4. Relative ./ (./src/index.ts, /project)
|
|
13
|
+
* 5. Relative ../ (../src/index.ts, /project) — escapes project
|
|
14
|
+
* 6. Empty/null (null / '' / undefined, /project)
|
|
15
|
+
*/
|
|
16
|
+
import { describe, it, expect } from 'vitest';
|
|
17
|
+
// ── normalizePathPure: 6 path types ──────────────────────────────────────────
|
|
18
|
+
describe('PRI-439 Phase 3: normalizePathPure — 6 path types', () => {
|
|
19
|
+
async function getModule() {
|
|
20
|
+
return import('../rule-host-input-builder.js');
|
|
21
|
+
}
|
|
22
|
+
// ── Type 1: Absolute POSIX ───────────────────────────────────────────────
|
|
23
|
+
it('type 1: absolute POSIX path relativizes to project dir', async () => {
|
|
24
|
+
const { normalizePathPure } = await getModule();
|
|
25
|
+
expect(normalizePathPure('/project/src/index.ts', '/project')).toBe('src/index.ts');
|
|
26
|
+
});
|
|
27
|
+
it('type 1: absolute POSIX path outside project returns original', async () => {
|
|
28
|
+
const { normalizePathPure } = await getModule();
|
|
29
|
+
expect(normalizePathPure('/etc/passwd', '/project')).toBe('/etc/passwd');
|
|
30
|
+
});
|
|
31
|
+
// ── Type 2: Absolute Windows ─────────────────────────────────────────────
|
|
32
|
+
it('type 2: absolute Windows path relativizes to Windows project dir', async () => {
|
|
33
|
+
const { normalizePathPure } = await getModule();
|
|
34
|
+
expect(normalizePathPure('D:\\project\\src\\index.ts', 'D:\\project')).toBe('src/index.ts');
|
|
35
|
+
});
|
|
36
|
+
it('type 2: absolute Windows path with forward slashes also works', async () => {
|
|
37
|
+
const { normalizePathPure } = await getModule();
|
|
38
|
+
expect(normalizePathPure('D:/project/src/index.ts', 'D:/project')).toBe('src/index.ts');
|
|
39
|
+
});
|
|
40
|
+
// ── Type 3: Relative bare ────────────────────────────────────────────────
|
|
41
|
+
it('type 3: relative bare path stays as-is when within project', async () => {
|
|
42
|
+
const { normalizePathPure } = await getModule();
|
|
43
|
+
expect(normalizePathPure('src/index.ts', '/project')).toBe('src/index.ts');
|
|
44
|
+
});
|
|
45
|
+
// ── Type 4: Relative ./ ──────────────────────────────────────────────────
|
|
46
|
+
it('type 4: relative ./ path normalizes to bare relative', async () => {
|
|
47
|
+
const { normalizePathPure } = await getModule();
|
|
48
|
+
expect(normalizePathPure('./src/index.ts', '/project')).toBe('src/index.ts');
|
|
49
|
+
});
|
|
50
|
+
// ── Type 5: Relative ../ (escapes project) ───────────────────────────────
|
|
51
|
+
it('type 5: relative ../ that escapes project returns original', async () => {
|
|
52
|
+
const { normalizePathPure } = await getModule();
|
|
53
|
+
expect(normalizePathPure('../src/index.ts', '/project')).toBe('../src/index.ts');
|
|
54
|
+
});
|
|
55
|
+
it('type 5: relative ../../ that escapes project returns original', async () => {
|
|
56
|
+
const { normalizePathPure } = await getModule();
|
|
57
|
+
expect(normalizePathPure('../../src/index.ts', '/project')).toBe('../../src/index.ts');
|
|
58
|
+
});
|
|
59
|
+
// ── Type 6: Empty/null ───────────────────────────────────────────────────
|
|
60
|
+
it('type 6: null returns empty string', async () => {
|
|
61
|
+
const { normalizePathPure } = await getModule();
|
|
62
|
+
expect(normalizePathPure(null, '/project')).toBe('');
|
|
63
|
+
});
|
|
64
|
+
it('type 6: undefined returns empty string', async () => {
|
|
65
|
+
const { normalizePathPure } = await getModule();
|
|
66
|
+
expect(normalizePathPure(undefined, '/project')).toBe('');
|
|
67
|
+
});
|
|
68
|
+
it('type 6: empty string returns empty string', async () => {
|
|
69
|
+
const { normalizePathPure } = await getModule();
|
|
70
|
+
expect(normalizePathPure('', '/project')).toBe('');
|
|
71
|
+
});
|
|
72
|
+
// ── Cross-platform determinism ───────────────────────────────────────────
|
|
73
|
+
it('produces same result for / and \\ separators', async () => {
|
|
74
|
+
const { normalizePathPure } = await getModule();
|
|
75
|
+
const posixResult = normalizePathPure('/project/src/index.ts', '/project');
|
|
76
|
+
const windowsResult = normalizePathPure('D:\\project\\src\\index.ts', 'D:\\project');
|
|
77
|
+
expect(posixResult).toBe('src/index.ts');
|
|
78
|
+
expect(windowsResult).toBe('src/index.ts');
|
|
79
|
+
expect(posixResult).toBe(windowsResult);
|
|
80
|
+
});
|
|
81
|
+
// ── Synthetic paths (production gate uses these for pathless write tools) ─
|
|
82
|
+
it('passes through synthetic <tool:...> paths unchanged', async () => {
|
|
83
|
+
const { normalizePathPure } = await getModule();
|
|
84
|
+
expect(normalizePathPure('<tool:apply_patch>', '/project')).toBe('<tool:apply_patch>');
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
// ── extractFilePathFromParams ────────────────────────────────────────────────
|
|
88
|
+
describe('PRI-439 Phase 3: extractFilePathFromParams', () => {
|
|
89
|
+
async function getModule() {
|
|
90
|
+
return import('../rule-host-input-builder.js');
|
|
91
|
+
}
|
|
92
|
+
it('extracts file_path from params', async () => {
|
|
93
|
+
const { extractFilePathFromParams } = await getModule();
|
|
94
|
+
expect(extractFilePathFromParams({ file_path: '/src/index.ts' })).toBe('/src/index.ts');
|
|
95
|
+
});
|
|
96
|
+
it('falls back to path if no file_path', async () => {
|
|
97
|
+
const { extractFilePathFromParams } = await getModule();
|
|
98
|
+
expect(extractFilePathFromParams({ path: '/src/index.ts' })).toBe('/src/index.ts');
|
|
99
|
+
});
|
|
100
|
+
it('falls back to file if no path', async () => {
|
|
101
|
+
const { extractFilePathFromParams } = await getModule();
|
|
102
|
+
expect(extractFilePathFromParams({ file: '/src/index.ts' })).toBe('/src/index.ts');
|
|
103
|
+
});
|
|
104
|
+
it('falls back to target if no file', async () => {
|
|
105
|
+
const { extractFilePathFromParams } = await getModule();
|
|
106
|
+
expect(extractFilePathFromParams({ target: '/src/index.ts' })).toBe('/src/index.ts');
|
|
107
|
+
});
|
|
108
|
+
it('returns null when no path-like param exists', async () => {
|
|
109
|
+
const { extractFilePathFromParams } = await getModule();
|
|
110
|
+
expect(extractFilePathFromParams({ command: 'echo hello' })).toBeNull();
|
|
111
|
+
});
|
|
112
|
+
it('returns null for empty params', async () => {
|
|
113
|
+
const { extractFilePathFromParams } = await getModule();
|
|
114
|
+
expect(extractFilePathFromParams({})).toBeNull();
|
|
115
|
+
});
|
|
116
|
+
it('returns synthetic <tool:...> for pathless write tools', async () => {
|
|
117
|
+
const { extractFilePathFromParams } = await getModule();
|
|
118
|
+
expect(extractFilePathFromParams({}, { isWriteTool: true, toolName: 'apply_patch' })).toBe('<tool:apply_patch>');
|
|
119
|
+
});
|
|
120
|
+
it('extracts file path from bash command mutation regex', async () => {
|
|
121
|
+
const { extractFilePathFromParams } = await getModule();
|
|
122
|
+
const result = extractFilePathFromParams({ command: 'rm -rf /tmp/foo' }, { isBashTool: true });
|
|
123
|
+
expect(result).toBe('/tmp/foo');
|
|
124
|
+
});
|
|
125
|
+
it('returns full bash command when no mutation target found', async () => {
|
|
126
|
+
const { extractFilePathFromParams } = await getModule();
|
|
127
|
+
const result = extractFilePathFromParams({ command: 'echo hello' }, { isBashTool: true });
|
|
128
|
+
expect(result).toBe('echo hello');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
// ── buildRuleHostAction: unified action snapshot ─────────────────────────────
|
|
132
|
+
describe('PRI-439 Phase 3: buildRuleHostAction — unified action snapshot', () => {
|
|
133
|
+
async function getModule() {
|
|
134
|
+
return import('../rule-host-input-builder.js');
|
|
135
|
+
}
|
|
136
|
+
it('produces action with toolName, normalizedPath, paramsSummary', async () => {
|
|
137
|
+
const { buildRuleHostAction } = await getModule();
|
|
138
|
+
const action = buildRuleHostAction('write', { file_path: '/project/src/index.ts' }, '/project');
|
|
139
|
+
expect(action.toolName).toBe('write');
|
|
140
|
+
expect(action.normalizedPath).toBe('src/index.ts');
|
|
141
|
+
expect(action.paramsSummary).toEqual({ file_path: '/project/src/index.ts' });
|
|
142
|
+
});
|
|
143
|
+
it('produces empty normalizedPath for null path', async () => {
|
|
144
|
+
const { buildRuleHostAction } = await getModule();
|
|
145
|
+
const action = buildRuleHostAction('write', {}, '/project');
|
|
146
|
+
expect(action.normalizedPath).toBe('');
|
|
147
|
+
});
|
|
148
|
+
it('produces synthetic path for pathless write tool', async () => {
|
|
149
|
+
const { buildRuleHostAction } = await getModule();
|
|
150
|
+
const action = buildRuleHostAction('apply_patch', {}, '/project', { isWriteTool: true });
|
|
151
|
+
expect(action.normalizedPath).toBe('<tool:apply_patch>');
|
|
152
|
+
});
|
|
153
|
+
it('produces same normalizedPath as direct normalizePathPure call', async () => {
|
|
154
|
+
const { buildRuleHostAction, normalizePathPure } = await getModule();
|
|
155
|
+
const action = buildRuleHostAction('edit', { file_path: '/project/src/test.ts' }, '/project');
|
|
156
|
+
const direct = normalizePathPure('/project/src/test.ts', '/project');
|
|
157
|
+
expect(action.normalizedPath).toBe(direct);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
// ── Golden Trace replay uses normalizePathPure (integration) ──────────────────
|
|
161
|
+
describe('PRI-439 Phase 3: Golden Trace replay produces non-null normalizedPath', () => {
|
|
162
|
+
it('createSyntheticRuleHostInput with projectDir produces normalized path from params', async () => {
|
|
163
|
+
const { createSyntheticRuleHostInput } = await import('../../golden-trace.js');
|
|
164
|
+
const input = createSyntheticRuleHostInput({ toolName: 'write', params: { file_path: '/project/src/secrets.env' } }, {}, { projectDir: '/project' });
|
|
165
|
+
expect(input.action.normalizedPath).toBe('src/secrets.env');
|
|
166
|
+
expect(input.action.normalizedPath).not.toBeNull();
|
|
167
|
+
});
|
|
168
|
+
it('createSyntheticRuleHostInput without projectDir falls back to null (backwards compat)', async () => {
|
|
169
|
+
const { createSyntheticRuleHostInput } = await import('../../golden-trace.js');
|
|
170
|
+
const input = createSyntheticRuleHostInput({ toolName: 'write', params: { file_path: '/project/src/secrets.env' } });
|
|
171
|
+
// Without projectDir, normalizedPath is null (backwards compat with existing callers)
|
|
172
|
+
expect(input.action.normalizedPath).toBeNull();
|
|
173
|
+
});
|
|
174
|
+
it('explicit normalizedPath override takes precedence over projectDir extraction', async () => {
|
|
175
|
+
const { createSyntheticRuleHostInput } = await import('../../golden-trace.js');
|
|
176
|
+
const input = createSyntheticRuleHostInput({ toolName: 'write', params: { file_path: '/project/src/secrets.env' } }, { normalizedPath: 'custom/path.ts' }, { projectDir: '/project' });
|
|
177
|
+
expect(input.action.normalizedPath).toBe('custom/path.ts');
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
//# sourceMappingURL=rule-host-input-builder.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-host-input-builder.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/internalization/__tests__/rule-host-input-builder.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,26 +1,13 @@
|
|
|
1
1
|
import { type Static } from '@sinclair/typebox';
|
|
2
2
|
import type { GoldenTraceDecision } from '../golden-trace.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
readonly changes: readonly string[];
|
|
7
|
-
readonly tests: readonly string[];
|
|
8
|
-
readonly rolloutNotes: readonly string[];
|
|
9
|
-
readonly confidence: number;
|
|
10
|
-
}
|
|
3
|
+
/**
|
|
4
|
+
* Artificer source trace — lineage back to upstream peer artifacts.
|
|
5
|
+
*/
|
|
11
6
|
export interface ArtificerSourceTrace {
|
|
12
7
|
readonly scribeArtifactId: string;
|
|
13
8
|
readonly philosopherArtifactId?: string;
|
|
14
9
|
readonly dreamerArtifactId?: string;
|
|
15
10
|
}
|
|
16
|
-
export interface ArtificerOutputV1 {
|
|
17
|
-
readonly taskId: string;
|
|
18
|
-
readonly sourceScribeArtifactId: string;
|
|
19
|
-
readonly implementationPlan: ArtificerImplementationPlan;
|
|
20
|
-
readonly sourceTrace: ArtificerSourceTrace;
|
|
21
|
-
readonly risks: readonly string[];
|
|
22
|
-
readonly generatedAt: string;
|
|
23
|
-
}
|
|
24
11
|
/**
|
|
25
12
|
* Artificer-generated golden trace case input (RuleHost MVP Activation, ADR-0014
|
|
26
13
|
* Amendment 2026-06-17 Decision 1).
|
|
@@ -40,51 +27,56 @@ export interface GoldenTraceCaseInput {
|
|
|
40
27
|
readonly expectedApplicationMode?: 'shadow' | 'live';
|
|
41
28
|
}
|
|
42
29
|
/**
|
|
43
|
-
*
|
|
30
|
+
* ArtificerRuleOutput — the UNIFIED Artificer output (PRI-439).
|
|
44
31
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
32
|
+
* Replaces the former V1/V2 dual-version system. `implementationCode` is now
|
|
33
|
+
* MANDATORY; there is no plan-only (V1) acceptance path and no degradation.
|
|
34
|
+
* Missing, invalid, or replay-failing RuleCode fails loud and creates no rule
|
|
35
|
+
* artifact, approval, or activation.
|
|
36
|
+
*
|
|
37
|
+
* `meta`, `taskId`, lineage, and `generatedAt` are server-injected / model-filled
|
|
38
|
+
* per the existing contract; the validator enforces their presence and consistency.
|
|
49
39
|
*/
|
|
50
|
-
export interface
|
|
40
|
+
export interface ArtificerRuleOutput {
|
|
41
|
+
readonly taskId: string;
|
|
42
|
+
readonly sourceScribeArtifactId: string;
|
|
51
43
|
readonly implementationCode: string;
|
|
52
44
|
readonly goldenTraceCases: readonly GoldenTraceCaseInput[];
|
|
53
45
|
readonly affectedTools: readonly string[];
|
|
46
|
+
readonly implementationSummary: string;
|
|
47
|
+
readonly risks: readonly string[];
|
|
48
|
+
readonly sourceTrace: ArtificerSourceTrace;
|
|
49
|
+
readonly generatedAt: string;
|
|
54
50
|
}
|
|
55
|
-
export declare const ArtificerImplementationPlanSchema: import("@sinclair/typebox").TObject<{
|
|
56
|
-
summary: import("@sinclair/typebox").TString;
|
|
57
|
-
targetSurface: import("@sinclair/typebox").TString;
|
|
58
|
-
changes: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
|
|
59
|
-
tests: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
|
|
60
|
-
rolloutNotes: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
|
|
61
|
-
confidence: import("@sinclair/typebox").TNumber;
|
|
62
|
-
}>;
|
|
63
51
|
export declare const ArtificerSourceTraceSchema: import("@sinclair/typebox").TObject<{
|
|
64
52
|
scribeArtifactId: import("@sinclair/typebox").TString;
|
|
65
53
|
philosopherArtifactId: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
66
54
|
dreamerArtifactId: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
67
55
|
}>;
|
|
68
|
-
export declare const
|
|
56
|
+
export declare const ArtificerRuleOutputSchema: import("@sinclair/typebox").TObject<{
|
|
69
57
|
taskId: import("@sinclair/typebox").TString;
|
|
70
58
|
sourceScribeArtifactId: import("@sinclair/typebox").TString;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
59
|
+
implementationCode: import("@sinclair/typebox").TString;
|
|
60
|
+
goldenTraceCases: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
61
|
+
caseId: import("@sinclair/typebox").TString;
|
|
62
|
+
kind: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"positive">, import("@sinclair/typebox").TLiteral<"negative">]>;
|
|
63
|
+
toolName: import("@sinclair/typebox").TString;
|
|
64
|
+
params: import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>;
|
|
65
|
+
expectedDecision: import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"allow">, import("@sinclair/typebox").TLiteral<"block">, import("@sinclair/typebox").TLiteral<"propose_correction">]>;
|
|
66
|
+
expectedProposedParams: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TUnknown>>;
|
|
67
|
+
expectedApplicationMode: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"shadow">, import("@sinclair/typebox").TLiteral<"live">]>>;
|
|
68
|
+
}>>;
|
|
69
|
+
affectedTools: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
|
|
70
|
+
implementationSummary: import("@sinclair/typebox").TString;
|
|
71
|
+
risks: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
|
|
79
72
|
sourceTrace: import("@sinclair/typebox").TObject<{
|
|
80
73
|
scribeArtifactId: import("@sinclair/typebox").TString;
|
|
81
74
|
philosopherArtifactId: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
82
75
|
dreamerArtifactId: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
83
76
|
}>;
|
|
84
|
-
risks: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>;
|
|
85
77
|
generatedAt: import("@sinclair/typebox").TString;
|
|
86
78
|
}>;
|
|
87
|
-
export type
|
|
79
|
+
export type ArtificerRuleOutputTB = Static<typeof ArtificerRuleOutputSchema>;
|
|
88
80
|
export interface ArtificerValidationResult {
|
|
89
81
|
readonly valid: boolean;
|
|
90
82
|
readonly errors: readonly string[];
|
|
@@ -94,16 +86,6 @@ export interface ArtificerValidator {
|
|
|
94
86
|
/** Validate untrusted output. Accepts `unknown` — must perform runtime checks (ERR-001). */
|
|
95
87
|
validate(output: unknown, taskId: string, expectedSourceScribeArtifactId?: string): Promise<ArtificerValidationResult>;
|
|
96
88
|
}
|
|
97
|
-
/**
|
|
98
|
-
* Runtime type guard distinguishing V2 (code-bearing) artificer output from V1.
|
|
99
|
-
* Use this — not `as ArtificerOutputV2` — after `validate()` succeeds to decide
|
|
100
|
-
* whether the rule-artifact assembly path applies (Runtime Contract Rule 2).
|
|
101
|
-
*
|
|
102
|
-
* Detection: V2 requires ALL three code fields present and well-formed. A
|
|
103
|
-
* partially-populated object is NOT V2 (it is malformed and will have been
|
|
104
|
-
* rejected by validate()).
|
|
105
|
-
*/
|
|
106
|
-
export declare function isArtificerOutputV2(output: unknown): output is ArtificerOutputV2;
|
|
107
89
|
export declare class DefaultArtificerValidator implements ArtificerValidator {
|
|
108
90
|
validate(output: unknown, taskId: string, expectedSourceScribeArtifactId?: string): Promise<ArtificerValidationResult>;
|
|
109
91
|
}
|