tryassay 0.15.1 → 0.17.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/__tests__/check-loop.test.d.ts +16 -0
- package/dist/runtime/__tests__/check-loop.test.js +437 -0
- package/dist/runtime/__tests__/check-loop.test.js.map +1 -0
- package/dist/runtime/__tests__/integration-verifier.test.d.ts +9 -0
- package/dist/runtime/__tests__/integration-verifier.test.js +120 -0
- package/dist/runtime/__tests__/integration-verifier.test.js.map +1 -0
- package/dist/runtime/app-create-orchestrator.js +42 -5
- package/dist/runtime/app-create-orchestrator.js.map +1 -1
- package/dist/runtime/check-definitions.d.ts +36 -0
- package/dist/runtime/check-definitions.js +238 -0
- package/dist/runtime/check-definitions.js.map +1 -0
- package/dist/runtime/check-loop.d.ts +27 -0
- package/dist/runtime/check-loop.js +66 -0
- package/dist/runtime/check-loop.js.map +1 -0
- package/dist/runtime/check-store.d.ts +24 -0
- package/dist/runtime/check-store.js +81 -0
- package/dist/runtime/check-store.js.map +1 -0
- package/dist/runtime/failure-classifier.d.ts +40 -0
- package/dist/runtime/failure-classifier.js +184 -0
- package/dist/runtime/failure-classifier.js.map +1 -0
- package/dist/runtime/fs-helpers.d.ts +20 -0
- package/dist/runtime/fs-helpers.js +122 -0
- package/dist/runtime/fs-helpers.js.map +1 -0
- package/dist/runtime/integration-verifier.d.ts +42 -0
- package/dist/runtime/integration-verifier.js +307 -0
- package/dist/runtime/integration-verifier.js.map +1 -0
- package/dist/runtime/types.d.ts +63 -0
- package/package.json +1 -1
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IntegrationVerifier — deterministic wiring checks for generated applications.
|
|
3
|
+
*
|
|
4
|
+
* Catches four classes of integration failure that compile clean but don't work:
|
|
5
|
+
* 1. Missing Router provider (pages use react-router hooks but no Router wraps them)
|
|
6
|
+
* 2. Missing IPC handlers (preload invokes channels with no main-process handler)
|
|
7
|
+
* 3. Stub functions (async functions that return literal objects without doing real work)
|
|
8
|
+
* 4. Unreachable pages (page files exist but are never imported from the entry point)
|
|
9
|
+
*
|
|
10
|
+
* Zero LLM calls. Deterministic. Uses only node:fs/promises, node:path, and regex.
|
|
11
|
+
*/
|
|
12
|
+
import { readFile } from 'node:fs/promises';
|
|
13
|
+
import { relative, basename, extname } from 'node:path';
|
|
14
|
+
import { findFiles, traceImports, findMatchingBrace } from './fs-helpers.js';
|
|
15
|
+
import { CheckExecutor } from './check-definitions.js';
|
|
16
|
+
import { CheckStore } from './check-store.js';
|
|
17
|
+
export class IntegrationVerifier {
|
|
18
|
+
projectPath;
|
|
19
|
+
framework;
|
|
20
|
+
constructor(projectPath, framework) {
|
|
21
|
+
this.projectPath = projectPath;
|
|
22
|
+
this.framework = framework;
|
|
23
|
+
}
|
|
24
|
+
async verify() {
|
|
25
|
+
const start = Date.now();
|
|
26
|
+
const checks = [];
|
|
27
|
+
// Run all checks
|
|
28
|
+
checks.push(...await this.checkRoutingProvider());
|
|
29
|
+
if (this.framework === 'electron' || await this.hasPreloadFiles()) {
|
|
30
|
+
checks.push(...await this.checkIpcHandlerCoverage());
|
|
31
|
+
checks.push(...await this.checkStubFunctions());
|
|
32
|
+
}
|
|
33
|
+
checks.push(...await this.checkUnreachablePages());
|
|
34
|
+
// Dynamic checks from CheckStore
|
|
35
|
+
try {
|
|
36
|
+
const store = new CheckStore();
|
|
37
|
+
const activeChecks = await store.getActive(this.framework);
|
|
38
|
+
if (activeChecks.length > 0) {
|
|
39
|
+
const executor = new CheckExecutor();
|
|
40
|
+
for (const def of activeChecks) {
|
|
41
|
+
checks.push(...await executor.execute(def, this.projectPath));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// CheckStore unavailable — continue with hardcoded checks only
|
|
47
|
+
}
|
|
48
|
+
const passedCount = checks.filter(c => c.verdict === 'PASS').length;
|
|
49
|
+
const failedCount = checks.filter(c => c.verdict === 'FAIL').length;
|
|
50
|
+
return {
|
|
51
|
+
checks,
|
|
52
|
+
passedCount,
|
|
53
|
+
failedCount,
|
|
54
|
+
verdict: failedCount > 0 ? 'FAIL' : 'PASS',
|
|
55
|
+
framework: this.framework,
|
|
56
|
+
totalDurationMs: Date.now() - start,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// ── Check 1: Routing Provider ──────────────────────────────
|
|
60
|
+
/**
|
|
61
|
+
* Scan all .tsx files for react-router hook usage.
|
|
62
|
+
* If found, verify a Router provider exists in the entry point chain.
|
|
63
|
+
*/
|
|
64
|
+
async checkRoutingProvider() {
|
|
65
|
+
const tsxFiles = await findFiles(this.projectPath, /\.(tsx|jsx)$/);
|
|
66
|
+
const routerHookPattern = /\b(useNavigate|useParams|useLocation|useSearchParams|useMatch|useRoutes)\b/;
|
|
67
|
+
const routerProviderPattern = /\b(BrowserRouter|HashRouter|MemoryRouter|RouterProvider|createBrowserRouter|createHashRouter|createMemoryRouter)\b/;
|
|
68
|
+
// Find files that use router hooks
|
|
69
|
+
const filesUsingHooks = [];
|
|
70
|
+
for (const file of tsxFiles) {
|
|
71
|
+
const content = await readFile(file, 'utf-8');
|
|
72
|
+
if (routerHookPattern.test(content)) {
|
|
73
|
+
filesUsingHooks.push(file);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (filesUsingHooks.length === 0) {
|
|
77
|
+
return []; // No router hooks used — nothing to check
|
|
78
|
+
}
|
|
79
|
+
// Check if ANY file in the project contains a Router provider
|
|
80
|
+
let providerFound = false;
|
|
81
|
+
let providerFile = '';
|
|
82
|
+
for (const file of tsxFiles) {
|
|
83
|
+
const content = await readFile(file, 'utf-8');
|
|
84
|
+
if (routerProviderPattern.test(content)) {
|
|
85
|
+
providerFound = true;
|
|
86
|
+
providerFile = relative(this.projectPath, file);
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (providerFound) {
|
|
91
|
+
return [{
|
|
92
|
+
type: 'routing_provider',
|
|
93
|
+
verdict: 'PASS',
|
|
94
|
+
evidence: `Router provider found in ${providerFile}. ${filesUsingHooks.length} file(s) use router hooks.`,
|
|
95
|
+
file: providerFile,
|
|
96
|
+
severity: 'critical',
|
|
97
|
+
}];
|
|
98
|
+
}
|
|
99
|
+
const hookFiles = filesUsingHooks.map(f => relative(this.projectPath, f)).join(', ');
|
|
100
|
+
return [{
|
|
101
|
+
type: 'routing_provider',
|
|
102
|
+
verdict: 'FAIL',
|
|
103
|
+
evidence: `${filesUsingHooks.length} file(s) use react-router hooks (${hookFiles}) but no Router provider (BrowserRouter, HashRouter, etc.) found in any .tsx file.`,
|
|
104
|
+
file: hookFiles,
|
|
105
|
+
severity: 'critical',
|
|
106
|
+
}];
|
|
107
|
+
}
|
|
108
|
+
// ── Check 2: IPC Handler Coverage ──────────────────────────
|
|
109
|
+
/**
|
|
110
|
+
* Electron only. Scan preload files for ipcRenderer.invoke calls.
|
|
111
|
+
* Scan main/ipc files for ipcMain.handle calls.
|
|
112
|
+
* Report any channel invoked but not handled.
|
|
113
|
+
*/
|
|
114
|
+
async checkIpcHandlerCoverage() {
|
|
115
|
+
const allFiles = await findFiles(this.projectPath, /\.(ts|tsx|js|jsx)$/);
|
|
116
|
+
// Find channels invoked in preload (renderer-side)
|
|
117
|
+
const invokedChannels = new Map(); // channel -> file
|
|
118
|
+
const invokePattern = /ipcRenderer\.invoke\(\s*['"`]([^'"`]+)['"`]/g;
|
|
119
|
+
for (const file of allFiles) {
|
|
120
|
+
const relPath = relative(this.projectPath, file);
|
|
121
|
+
if (!relPath.includes('preload'))
|
|
122
|
+
continue;
|
|
123
|
+
const content = await readFile(file, 'utf-8');
|
|
124
|
+
let match;
|
|
125
|
+
while ((match = invokePattern.exec(content)) !== null) {
|
|
126
|
+
invokedChannels.set(match[1], relPath);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (invokedChannels.size === 0) {
|
|
130
|
+
return []; // No IPC invoke calls found
|
|
131
|
+
}
|
|
132
|
+
// Find channels handled in main process
|
|
133
|
+
const handledChannels = new Set();
|
|
134
|
+
const handlePattern = /ipcMain\.handle\(\s*['"`]([^'"`]+)['"`]/g;
|
|
135
|
+
// Also check for IPC_CHANNELS.CONSTANT patterns that resolve to string literals
|
|
136
|
+
const channelConstPattern = /ipcMain\.handle\(\s*(?:IPC_CHANNELS\.\w+|[\w.]+)\s*,/g;
|
|
137
|
+
for (const file of allFiles) {
|
|
138
|
+
const relPath = relative(this.projectPath, file);
|
|
139
|
+
// Check main process files (main/, ipc/, handlers/)
|
|
140
|
+
if (!relPath.includes('main') && !relPath.includes('ipc') && !relPath.includes('handler'))
|
|
141
|
+
continue;
|
|
142
|
+
const content = await readFile(file, 'utf-8');
|
|
143
|
+
// Direct string channel handles
|
|
144
|
+
let match;
|
|
145
|
+
while ((match = handlePattern.exec(content)) !== null) {
|
|
146
|
+
handledChannels.add(match[1]);
|
|
147
|
+
}
|
|
148
|
+
// Also resolve IPC_CHANNELS constants by scanning for their definitions
|
|
149
|
+
const constDefPattern = /['"`]([^'"`]+)['"`]\s*(?:,|as\s+const)/g;
|
|
150
|
+
if (relPath.includes('handler') || relPath.includes('ipc')) {
|
|
151
|
+
while ((match = constDefPattern.exec(content)) !== null) {
|
|
152
|
+
// Only add if it looks like a channel name (contains colon)
|
|
153
|
+
if (match[1].includes(':')) {
|
|
154
|
+
handledChannels.add(match[1]);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Also scan shared types for IPC_CHANNELS constant definitions
|
|
160
|
+
for (const file of allFiles) {
|
|
161
|
+
const relPath = relative(this.projectPath, file);
|
|
162
|
+
if (!relPath.includes('shared') && !relPath.includes('types'))
|
|
163
|
+
continue;
|
|
164
|
+
const content = await readFile(file, 'utf-8');
|
|
165
|
+
const channelValuePattern = /:\s*['"`]([^'"`]+)['"`]/g;
|
|
166
|
+
if (content.includes('IPC_CHANNELS')) {
|
|
167
|
+
let match;
|
|
168
|
+
while ((match = channelValuePattern.exec(content)) !== null) {
|
|
169
|
+
if (match[1].includes(':')) {
|
|
170
|
+
handledChannels.add(match[1]);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const checks = [];
|
|
176
|
+
for (const [channel, invokeFile] of invokedChannels) {
|
|
177
|
+
if (handledChannels.has(channel)) {
|
|
178
|
+
checks.push({
|
|
179
|
+
type: 'ipc_handler_coverage',
|
|
180
|
+
verdict: 'PASS',
|
|
181
|
+
evidence: `Channel '${channel}' invoked in ${invokeFile} has a matching handler.`,
|
|
182
|
+
file: invokeFile,
|
|
183
|
+
severity: 'critical',
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
checks.push({
|
|
188
|
+
type: 'ipc_handler_coverage',
|
|
189
|
+
verdict: 'FAIL',
|
|
190
|
+
evidence: `Channel '${channel}' invoked in ${invokeFile} has NO handler in any main-process file.`,
|
|
191
|
+
file: invokeFile,
|
|
192
|
+
severity: 'critical',
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return checks;
|
|
197
|
+
}
|
|
198
|
+
// ── Check 3: Stub Functions ────────────────────────────────
|
|
199
|
+
/**
|
|
200
|
+
* Find async functions in preload whose body is ONLY a return of a literal object
|
|
201
|
+
* without ipcRenderer.invoke, await, .query(), or fetch().
|
|
202
|
+
*/
|
|
203
|
+
async checkStubFunctions() {
|
|
204
|
+
const allFiles = await findFiles(this.projectPath, /\.(ts|tsx|js|jsx)$/);
|
|
205
|
+
const checks = [];
|
|
206
|
+
for (const file of allFiles) {
|
|
207
|
+
const relPath = relative(this.projectPath, file);
|
|
208
|
+
if (!relPath.includes('preload'))
|
|
209
|
+
continue;
|
|
210
|
+
const content = await readFile(file, 'utf-8');
|
|
211
|
+
const lines = content.split('\n');
|
|
212
|
+
// Find async arrow functions that return a literal object without real work
|
|
213
|
+
// Pattern: async (params) => { return { ... }; } or async (params): Promise<...> => { return { ... }; }
|
|
214
|
+
// But NOT functions that contain ipcRenderer.invoke, await (something), fetch, .query()
|
|
215
|
+
const stubPattern = /async\s+\(([^)]*)\)\s*(?::\s*Promise<[^>]+>)?\s*=>\s*\{/g;
|
|
216
|
+
let match;
|
|
217
|
+
while ((match = stubPattern.exec(content)) !== null) {
|
|
218
|
+
const startIdx = match.index + match[0].length;
|
|
219
|
+
const bodyEnd = findMatchingBrace(content, startIdx - 1);
|
|
220
|
+
if (bodyEnd === -1)
|
|
221
|
+
continue;
|
|
222
|
+
const body = content.slice(startIdx, bodyEnd).trim();
|
|
223
|
+
const hasRealWork = /ipcRenderer\.invoke|await\s+[^{]|\.query\(|fetch\(|\.send\(|\.emit\(/.test(body);
|
|
224
|
+
const isLiteralReturn = /^\s*return\s+\{[^}]*\}\s*;?\s*$/.test(body);
|
|
225
|
+
if (isLiteralReturn && !hasRealWork) {
|
|
226
|
+
// Find the function name by looking at what precedes the async keyword
|
|
227
|
+
const preceding = content.slice(Math.max(0, match.index - 80), match.index);
|
|
228
|
+
const nameMatch = preceding.match(/(\w+)\s*:\s*$/);
|
|
229
|
+
const funcName = nameMatch ? nameMatch[1] : 'anonymous';
|
|
230
|
+
// Find line number
|
|
231
|
+
const lineNum = content.slice(0, match.index).split('\n').length;
|
|
232
|
+
checks.push({
|
|
233
|
+
type: 'stub_function',
|
|
234
|
+
verdict: 'FAIL',
|
|
235
|
+
evidence: `Function '${funcName}' at line ${lineNum} is a stub: returns a literal object without ipcRenderer.invoke or any real operation. Body: ${body.trim()}`,
|
|
236
|
+
file: relPath,
|
|
237
|
+
severity: 'high',
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return checks;
|
|
243
|
+
}
|
|
244
|
+
// ── Check 4: Unreachable Pages ─────────────────────────────
|
|
245
|
+
/**
|
|
246
|
+
* Collect page files from pages/ directories.
|
|
247
|
+
* Build import graph from entry point.
|
|
248
|
+
* Report any page file not transitively imported.
|
|
249
|
+
*/
|
|
250
|
+
async checkUnreachablePages() {
|
|
251
|
+
// Find page files
|
|
252
|
+
const allFiles = await findFiles(this.projectPath, /\.(tsx|jsx|ts|js)$/);
|
|
253
|
+
const pageFiles = allFiles.filter(f => {
|
|
254
|
+
const rel = relative(this.projectPath, f);
|
|
255
|
+
return rel.includes('pages/') || rel.includes('pages\\');
|
|
256
|
+
});
|
|
257
|
+
if (pageFiles.length === 0) {
|
|
258
|
+
return []; // No pages directory
|
|
259
|
+
}
|
|
260
|
+
// Find entry point (file with createRoot or ReactDOM.render)
|
|
261
|
+
let entryFile = null;
|
|
262
|
+
for (const file of allFiles) {
|
|
263
|
+
const content = await readFile(file, 'utf-8');
|
|
264
|
+
if (/createRoot|ReactDOM\.render/.test(content)) {
|
|
265
|
+
entryFile = file;
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (!entryFile) {
|
|
270
|
+
return []; // No entry point found — can't trace imports
|
|
271
|
+
}
|
|
272
|
+
// Build transitive import graph from entry point
|
|
273
|
+
const reachable = new Set();
|
|
274
|
+
await traceImports(entryFile, reachable, allFiles);
|
|
275
|
+
const checks = [];
|
|
276
|
+
for (const pageFile of pageFiles) {
|
|
277
|
+
const relPath = relative(this.projectPath, pageFile);
|
|
278
|
+
const pageName = basename(pageFile, extname(pageFile));
|
|
279
|
+
if (reachable.has(pageFile)) {
|
|
280
|
+
checks.push({
|
|
281
|
+
type: 'unreachable_page',
|
|
282
|
+
verdict: 'PASS',
|
|
283
|
+
evidence: `Page '${pageName}' (${relPath}) is reachable from entry point.`,
|
|
284
|
+
file: relPath,
|
|
285
|
+
severity: 'high',
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
checks.push({
|
|
290
|
+
type: 'unreachable_page',
|
|
291
|
+
verdict: 'FAIL',
|
|
292
|
+
evidence: `Page '${pageName}' (${relPath}) is NOT imported from the entry point chain. It exists as a file but is unreachable at runtime.`,
|
|
293
|
+
file: relPath,
|
|
294
|
+
severity: 'high',
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return checks;
|
|
299
|
+
}
|
|
300
|
+
// ── Helpers ────────────────────────────────────────────────
|
|
301
|
+
/** Check if the project has preload files (indicating Electron). */
|
|
302
|
+
async hasPreloadFiles() {
|
|
303
|
+
const files = await findFiles(this.projectPath, /\.(ts|tsx|js|jsx)$/);
|
|
304
|
+
return files.some(f => relative(this.projectPath, f).includes('preload'));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=integration-verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration-verifier.js","sourceRoot":"","sources":["../../src/runtime/integration-verifier.ts"],"names":[],"mappings":"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"}
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -1378,6 +1378,8 @@ export type AppCreatePhase = {
|
|
|
1378
1378
|
readonly attempt: number;
|
|
1379
1379
|
readonly maxAttempts: number;
|
|
1380
1380
|
readonly errorCount: number;
|
|
1381
|
+
} | {
|
|
1382
|
+
readonly phase: 'integration_verifying';
|
|
1381
1383
|
} | {
|
|
1382
1384
|
readonly phase: 'cross_verifying';
|
|
1383
1385
|
} | {
|
|
@@ -1402,6 +1404,7 @@ export interface AppCreateResult {
|
|
|
1402
1404
|
readonly plan: ArchitecturePlan | null;
|
|
1403
1405
|
readonly featureResults: readonly FeatureBuildResult[];
|
|
1404
1406
|
readonly buildVerification: BuildVerificationResult | null;
|
|
1407
|
+
readonly integrationVerification: IntegrationVerificationResult | null;
|
|
1405
1408
|
readonly crossVerification: CrossFeatureVerification | null;
|
|
1406
1409
|
readonly totalDurationMs: number;
|
|
1407
1410
|
readonly auditTrail: readonly AuditEntry[];
|
|
@@ -1431,6 +1434,22 @@ export interface CrossFeatureCheck {
|
|
|
1431
1434
|
readonly verdict: 'PASS' | 'FAIL';
|
|
1432
1435
|
readonly evidence: string;
|
|
1433
1436
|
}
|
|
1437
|
+
export type IntegrationCheckType = 'routing_provider' | 'ipc_handler_coverage' | 'stub_function' | 'unreachable_page';
|
|
1438
|
+
export interface IntegrationCheck {
|
|
1439
|
+
readonly type: IntegrationCheckType;
|
|
1440
|
+
readonly verdict: 'PASS' | 'FAIL';
|
|
1441
|
+
readonly evidence: string;
|
|
1442
|
+
readonly file: string;
|
|
1443
|
+
readonly severity: 'critical' | 'high' | 'medium';
|
|
1444
|
+
}
|
|
1445
|
+
export interface IntegrationVerificationResult {
|
|
1446
|
+
readonly checks: readonly IntegrationCheck[];
|
|
1447
|
+
readonly passedCount: number;
|
|
1448
|
+
readonly failedCount: number;
|
|
1449
|
+
readonly verdict: 'PASS' | 'FAIL';
|
|
1450
|
+
readonly framework: string;
|
|
1451
|
+
readonly totalDurationMs: number;
|
|
1452
|
+
}
|
|
1434
1453
|
export type BuildStepStatus = 'pass' | 'fail' | 'skip' | 'timeout';
|
|
1435
1454
|
export interface BuildStepResult {
|
|
1436
1455
|
readonly step: 'install' | 'build' | 'start' | 'health_check';
|
|
@@ -1477,3 +1496,47 @@ export interface AppCreateOptions {
|
|
|
1477
1496
|
readonly maxBuildRepairAttempts?: number;
|
|
1478
1497
|
readonly skipBuildVerification?: boolean;
|
|
1479
1498
|
}
|
|
1499
|
+
export type CheckStrategyType = 'pattern_presence' | 'pattern_absence' | 'cross_reference' | 'import_reachability';
|
|
1500
|
+
export interface PatternPresenceStrategy {
|
|
1501
|
+
readonly type: 'pattern_presence';
|
|
1502
|
+
readonly fileGlob: string;
|
|
1503
|
+
readonly pattern: string;
|
|
1504
|
+
readonly requireIn: 'any' | 'all';
|
|
1505
|
+
readonly contextGlob?: string;
|
|
1506
|
+
readonly contextPattern?: string;
|
|
1507
|
+
}
|
|
1508
|
+
export interface PatternAbsenceStrategy {
|
|
1509
|
+
readonly type: 'pattern_absence';
|
|
1510
|
+
readonly fileGlob: string;
|
|
1511
|
+
readonly pattern: string;
|
|
1512
|
+
readonly allowIn?: readonly string[];
|
|
1513
|
+
}
|
|
1514
|
+
export interface CrossReferenceStrategy {
|
|
1515
|
+
readonly type: 'cross_reference';
|
|
1516
|
+
readonly sourceGlob: string;
|
|
1517
|
+
readonly sourcePattern: string;
|
|
1518
|
+
readonly targetGlob: string;
|
|
1519
|
+
readonly targetPattern: string;
|
|
1520
|
+
}
|
|
1521
|
+
export interface ImportReachabilityStrategy {
|
|
1522
|
+
readonly type: 'import_reachability';
|
|
1523
|
+
readonly pageGlob: string;
|
|
1524
|
+
readonly entryPattern: string;
|
|
1525
|
+
}
|
|
1526
|
+
export type CheckStrategy = PatternPresenceStrategy | PatternAbsenceStrategy | CrossReferenceStrategy | ImportReachabilityStrategy;
|
|
1527
|
+
export interface IntegrationCheckDefinition {
|
|
1528
|
+
readonly id: string;
|
|
1529
|
+
readonly name: string;
|
|
1530
|
+
readonly type: string;
|
|
1531
|
+
readonly strategy: CheckStrategy;
|
|
1532
|
+
readonly severity: 'critical' | 'high' | 'medium';
|
|
1533
|
+
readonly frameworks: readonly string[];
|
|
1534
|
+
readonly status: 'proposed' | 'shadow' | 'active' | 'deprecated';
|
|
1535
|
+
readonly createdAt: string;
|
|
1536
|
+
readonly evidenceTemplate: string;
|
|
1537
|
+
}
|
|
1538
|
+
export interface CheckLoopResult {
|
|
1539
|
+
readonly proposedChecks: readonly IntegrationCheckDefinition[];
|
|
1540
|
+
readonly duplicatesSkipped: number;
|
|
1541
|
+
readonly classificationErrors: number;
|
|
1542
|
+
}
|