imprint-mcp 0.6.0 → 0.6.2
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/README.md +2 -0
- package/package.json +4 -2
- package/prompts/audit-agent.md +4 -2
- package/prompts/auth-compile-agent.md +149 -158
- package/prompts/build-planning.md +14 -9
- package/prompts/compile-agent.md +46 -23
- package/prompts/live-verifier-agent.md +101 -0
- package/prompts/playbook-compilation.md +8 -1
- package/prompts/tool-candidate-detection.md +9 -29
- package/src/cli.ts +83 -1
- package/src/imprint/audit.ts +219 -20
- package/src/imprint/auth-compile-agent.ts +215 -155
- package/src/imprint/auth-compile-tools.ts +300 -118
- package/src/imprint/auth-verifier.ts +167 -180
- package/src/imprint/backend-cache.ts +18 -11
- package/src/imprint/backend-ladder.ts +225 -177
- package/src/imprint/build-plan.ts +3 -8
- package/src/imprint/cdp-browser-fetch.ts +930 -83
- package/src/imprint/claude-cli-compile.ts +46 -20
- package/src/imprint/codex-cli-compile.ts +436 -139
- package/src/imprint/compile-agent-types.ts +15 -10
- package/src/imprint/compile-agent.ts +88 -28
- package/src/imprint/compile-tools.ts +228 -39
- package/src/imprint/compile-verification.ts +187 -0
- package/src/imprint/compile.ts +71 -2
- package/src/imprint/credential-store.ts +57 -44
- package/src/imprint/emit.ts +3 -1
- package/src/imprint/freeform-redact.ts +27 -6
- package/src/imprint/live-verifier.ts +1665 -0
- package/src/imprint/llm.ts +22 -3
- package/src/imprint/login.ts +107 -25
- package/src/imprint/mcp-compile-server.ts +447 -114
- package/src/imprint/mcp-live-verifier-server.ts +359 -0
- package/src/imprint/mcp-server.ts +116 -35
- package/src/imprint/probe-backends.ts +88 -7
- package/src/imprint/recording-request.ts +36 -0
- package/src/imprint/request-capture.ts +40 -17
- package/src/imprint/runtime.ts +490 -337
- package/src/imprint/teach-state.ts +36 -2
- package/src/imprint/teach.ts +302 -146
- package/src/imprint/tool-candidates.ts +8 -10
- package/src/imprint/tool-loader.ts +12 -4
- package/src/imprint/types.ts +137 -68
package/src/imprint/audit.ts
CHANGED
|
@@ -94,6 +94,74 @@ interface AuditScore {
|
|
|
94
94
|
verdict: 'pass' | 'fail' | 'inconclusive' | 'timeout';
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
interface ExpectedAuditTool {
|
|
98
|
+
name: string;
|
|
99
|
+
parameters: readonly string[];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
interface MissingAuditedParameter {
|
|
103
|
+
tool: string;
|
|
104
|
+
name: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
interface AuditEvaluation {
|
|
108
|
+
score: AuditScore;
|
|
109
|
+
missingTools: string[];
|
|
110
|
+
missingParameters: MissingAuditedParameter[];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Restrict an agent-authored report to the connected workflows before it is
|
|
115
|
+
* scored. Agent output is not a trusted inventory: it can repeat a tool or a
|
|
116
|
+
* parameter, or mention a tool that was never connected. Taking the first
|
|
117
|
+
* report for each expected name keeps the result deterministic and, more
|
|
118
|
+
* importantly, prevents repeated/unknown positive verdicts from inflating the
|
|
119
|
+
* acceptance score. Later duplicates remain available in the persisted raw
|
|
120
|
+
* report for diagnosis; they simply carry no grading weight.
|
|
121
|
+
*/
|
|
122
|
+
function normalizeAuditReport(
|
|
123
|
+
report: AuditReport,
|
|
124
|
+
expectedTools: readonly ExpectedAuditTool[],
|
|
125
|
+
): AuditReport {
|
|
126
|
+
const firstToolByName = new Map<string, AuditReport['tools'][number]>();
|
|
127
|
+
for (const tool of report.tools) {
|
|
128
|
+
if (!firstToolByName.has(tool.name)) firstToolByName.set(tool.name, tool);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const normalizedTools: AuditReport['tools'] = [];
|
|
132
|
+
const seenExpectedTools = new Set<string>();
|
|
133
|
+
for (const expected of expectedTools) {
|
|
134
|
+
if (seenExpectedTools.has(expected.name)) continue;
|
|
135
|
+
seenExpectedTools.add(expected.name);
|
|
136
|
+
|
|
137
|
+
const reported = firstToolByName.get(expected.name);
|
|
138
|
+
if (!reported) continue;
|
|
139
|
+
|
|
140
|
+
const firstParameterByName = new Map<
|
|
141
|
+
string,
|
|
142
|
+
AuditReport['tools'][number]['parameters'][number]
|
|
143
|
+
>();
|
|
144
|
+
for (const parameter of reported.parameters) {
|
|
145
|
+
if (!firstParameterByName.has(parameter.name)) {
|
|
146
|
+
firstParameterByName.set(parameter.name, parameter);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const parameters: AuditReport['tools'][number]['parameters'] = [];
|
|
151
|
+
const seenExpectedParameters = new Set<string>();
|
|
152
|
+
for (const name of expected.parameters) {
|
|
153
|
+
if (seenExpectedParameters.has(name)) continue;
|
|
154
|
+
seenExpectedParameters.add(name);
|
|
155
|
+
const parameter = firstParameterByName.get(name);
|
|
156
|
+
if (parameter) parameters.push(parameter);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
normalizedTools.push({ ...reported, parameters });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return { ...report, tools: normalizedTools };
|
|
163
|
+
}
|
|
164
|
+
|
|
97
165
|
/**
|
|
98
166
|
* Pure, deterministic scoring over the model's verdicts.
|
|
99
167
|
*
|
|
@@ -107,7 +175,7 @@ interface AuditScore {
|
|
|
107
175
|
* - `score = 100 * correct / graded` (0 when nothing was gradeable).
|
|
108
176
|
* - Verdict: no gradeable invocations → `inconclusive` (re-run / site blocked
|
|
109
177
|
* us, not a code fail). Otherwise `pass` requires both `score >= minScore`
|
|
110
|
-
* AND at least
|
|
178
|
+
* AND at least one gradeable unit per gradeable tool, where
|
|
111
179
|
* `gradeableTools` is the number of tools that produced ≥1 gradeable
|
|
112
180
|
* invocation. Scaling the signal floor to *gradeable* tools (not all tools)
|
|
113
181
|
* means a tool the auditor can never exercise — e.g. one that needs an opaque
|
|
@@ -175,7 +243,7 @@ export function computeAuditScore(report: AuditReport, minScore: number): AuditS
|
|
|
175
243
|
}
|
|
176
244
|
const graded = correct + broken;
|
|
177
245
|
const score = graded === 0 ? 0 : (100 * correct) / graded;
|
|
178
|
-
const minGraded = Math.max(
|
|
246
|
+
const minGraded = Math.max(1, gradeableTools);
|
|
179
247
|
let verdict: AuditScore['verdict'];
|
|
180
248
|
if (graded === 0) {
|
|
181
249
|
verdict = 'inconclusive';
|
|
@@ -223,6 +291,82 @@ export function ungradeableToolNames(report: AuditReport): string[] {
|
|
|
223
291
|
return report.tools.filter((t) => !toolHasGradeableAuditSignal(t)).map((t) => t.name);
|
|
224
292
|
}
|
|
225
293
|
|
|
294
|
+
/** Connected tools for which the auditor reported no invocation attempt.
|
|
295
|
+
* Merely naming a tool (or reporting parameter verdicts) is not evidence that
|
|
296
|
+
* its core operation was called. This is distinct from an ungradeable tool: an
|
|
297
|
+
* explicit infra/bad_params invocation is useful attempt evidence, while zero
|
|
298
|
+
* invocation records gives us no evidence that the auditor called it at all. */
|
|
299
|
+
export function missingAuditedToolNames(
|
|
300
|
+
report: AuditReport,
|
|
301
|
+
expectedToolNames: readonly string[],
|
|
302
|
+
): string[] {
|
|
303
|
+
const attemptedNames = new Set(
|
|
304
|
+
report.tools.filter((tool) => tool.invocations.length > 0).map((tool) => tool.name),
|
|
305
|
+
);
|
|
306
|
+
return expectedToolNames.filter((name) => !attemptedNames.has(name));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** Advertised workflow parameters absent from the auditor's final report.
|
|
310
|
+
* Every explicit parameter verdict counts as coverage, including `untestable`:
|
|
311
|
+
* the latter is an honest result, while omission provides no evidence that the
|
|
312
|
+
* auditor considered the parameter at all. */
|
|
313
|
+
export function missingAuditedParameters(
|
|
314
|
+
report: AuditReport,
|
|
315
|
+
expectedTools: readonly ExpectedAuditTool[],
|
|
316
|
+
): MissingAuditedParameter[] {
|
|
317
|
+
const reportedParameters = new Map<string, Set<string>>();
|
|
318
|
+
for (const tool of report.tools) {
|
|
319
|
+
const names = reportedParameters.get(tool.name) ?? new Set<string>();
|
|
320
|
+
for (const parameter of tool.parameters) names.add(parameter.name);
|
|
321
|
+
reportedParameters.set(tool.name, names);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const missing: MissingAuditedParameter[] = [];
|
|
325
|
+
for (const tool of expectedTools) {
|
|
326
|
+
const covered = reportedParameters.get(tool.name) ?? new Set<string>();
|
|
327
|
+
for (const name of tool.parameters) {
|
|
328
|
+
if (!covered.has(name)) missing.push({ tool: tool.name, name });
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return missing;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** Complete deterministic audit evaluation, including report coverage. A high
|
|
335
|
+
* score cannot pass when the auditor omitted a connected tool or advertised
|
|
336
|
+
* parameter; timeouts remain the highest-priority terminal verdict. */
|
|
337
|
+
export function evaluateAuditReport(
|
|
338
|
+
report: AuditReport,
|
|
339
|
+
minScore: number,
|
|
340
|
+
expectedTools: readonly ExpectedAuditTool[],
|
|
341
|
+
timedOut = false,
|
|
342
|
+
): AuditEvaluation {
|
|
343
|
+
const normalizedReport = normalizeAuditReport(report, expectedTools);
|
|
344
|
+
const rawScore = computeAuditScore(normalizedReport, minScore);
|
|
345
|
+
const missingTools = missingAuditedToolNames(
|
|
346
|
+
normalizedReport,
|
|
347
|
+
expectedTools.map((tool) => tool.name),
|
|
348
|
+
);
|
|
349
|
+
const missingParameters = missingAuditedParameters(normalizedReport, expectedTools);
|
|
350
|
+
|
|
351
|
+
let verdict = rawScore.verdict;
|
|
352
|
+
if (timedOut) {
|
|
353
|
+
verdict = 'timeout';
|
|
354
|
+
} else if (
|
|
355
|
+
rawScore.verdict === 'pass' &&
|
|
356
|
+
(!auditHasCorrectSignal(normalizedReport) ||
|
|
357
|
+
missingTools.length > 0 ||
|
|
358
|
+
missingParameters.length > 0)
|
|
359
|
+
) {
|
|
360
|
+
verdict = 'inconclusive';
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return {
|
|
364
|
+
score: { ...rawScore, verdict },
|
|
365
|
+
missingTools,
|
|
366
|
+
missingParameters,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
226
370
|
/** Advertised parameters the auditor could not differentially test (opaque enum
|
|
227
371
|
* with no constructible value, or a state-changing/bot-defended tool). Surfaced
|
|
228
372
|
* so an unverifiable parameter is visible rather than silently passing. */
|
|
@@ -250,6 +394,17 @@ interface RunAuditOptions {
|
|
|
250
394
|
json?: boolean;
|
|
251
395
|
}
|
|
252
396
|
|
|
397
|
+
export function buildAuditMcpEnvironment(assetRoot = imprintHomeDir()): Record<string, string> {
|
|
398
|
+
return {
|
|
399
|
+
// Codex MCP server `env` entries are an explicit environment, so relying on
|
|
400
|
+
// the audit driver's inherited IMPRINT_HOME can make an isolated audit
|
|
401
|
+
// silently fall back to ~/.imprint and expose stale tools.
|
|
402
|
+
IMPRINT_HOME: assetRoot,
|
|
403
|
+
IMPRINT_AUDIT_PACING_MS: '5000',
|
|
404
|
+
IMPRINT_AUDIT_TOOL_DEADLINE_MS: '120000',
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
253
408
|
export async function runAudit(opts: RunAuditOptions): Promise<AuditScore> {
|
|
254
409
|
return await traced(
|
|
255
410
|
'audit.session',
|
|
@@ -278,7 +433,11 @@ export async function runAudit(opts: RunAuditOptions): Promise<AuditScore> {
|
|
|
278
433
|
);
|
|
279
434
|
}
|
|
280
435
|
|
|
281
|
-
const
|
|
436
|
+
const expectedTools = tools.map((tool) => ({
|
|
437
|
+
name: tool.workflow.toolName,
|
|
438
|
+
parameters: tool.workflow.parameters.map((parameter) => parameter.name),
|
|
439
|
+
}));
|
|
440
|
+
const toolNames = expectedTools.map((tool) => tool.name);
|
|
282
441
|
log(`auditing ${toolCount} tool(s) for site "${opts.site}": ${toolNames.join(', ')}`);
|
|
283
442
|
|
|
284
443
|
// Parameters that shipped live-unverified at compile time (Fix D). Tell the
|
|
@@ -320,8 +479,6 @@ export async function runAudit(opts: RunAuditOptions): Promise<AuditScore> {
|
|
|
320
479
|
tokenDeps,
|
|
321
480
|
});
|
|
322
481
|
|
|
323
|
-
const rawScore = computeAuditScore(drive.report, opts.minScore);
|
|
324
|
-
|
|
325
482
|
// Cross-reference compile-time live verification with the audit grade.
|
|
326
483
|
// The downgrade rule's purpose is to surface "flying blind" runs —
|
|
327
484
|
// ones where the gate has no positive evidence the framework works
|
|
@@ -331,7 +488,7 @@ export async function runAudit(opts: RunAuditOptions): Promise<AuditScore> {
|
|
|
331
488
|
// chained tool was unreachable from auditor's connected set).
|
|
332
489
|
// v2: downgrade only if a flying-blind tool had infra invocations
|
|
333
490
|
// → still over-attributed transient page-state to defects.
|
|
334
|
-
// v3
|
|
491
|
+
// v3: downgrade only when the audit produced ZERO
|
|
335
492
|
// `correct` invocations across ALL tools. If even one
|
|
336
493
|
// invocation graded correctly, that's positive evidence the
|
|
337
494
|
// framework + runtime work for at least that tool — the
|
|
@@ -339,21 +496,32 @@ export async function runAudit(opts: RunAuditOptions): Promise<AuditScore> {
|
|
|
339
496
|
// signal. Tools that couldn't be exercised still surface via
|
|
340
497
|
// `ungradeableTools` / `unverifiedAndUngradeable` for visibility
|
|
341
498
|
// without spoiling a verdict the score honestly earned.
|
|
499
|
+
// v4: retain v3's treatment of tools explicitly reported as
|
|
500
|
+
// blocked, but require every connected tool to appear in the final
|
|
501
|
+
// report. An omitted tool has no audit evidence at all, so a report
|
|
502
|
+
// covering only a successful subset is inconclusive rather than a
|
|
503
|
+
// pass.
|
|
504
|
+
// v5: likewise require an explicit verdict for every
|
|
505
|
+
// advertised workflow parameter. `untestable` is valid coverage;
|
|
506
|
+
// silently omitting a parameter is not.
|
|
507
|
+
// v6 (current): a connected tool must have at least one invocation
|
|
508
|
+
// record. Merely naming it in the report or discussing its
|
|
509
|
+
// parameters is not evidence that its core operation was attempted;
|
|
510
|
+
// infra and bad_params invocations still count as honest attempts.
|
|
342
511
|
const ungradeableNames = ungradeableToolNames(drive.report);
|
|
512
|
+
const evaluation = evaluateAuditReport(
|
|
513
|
+
drive.report,
|
|
514
|
+
opts.minScore,
|
|
515
|
+
expectedTools,
|
|
516
|
+
drive.timedOut,
|
|
517
|
+
);
|
|
518
|
+
const { missingTools: missingToolNames, missingParameters } = evaluation;
|
|
343
519
|
const untestableParamList = untestableParams(drive.report);
|
|
344
520
|
const unverifiedAndUngradeable = tools
|
|
345
521
|
.filter((t) => t.workflow.liveVerified === false)
|
|
346
522
|
.map((t) => t.workflow.toolName)
|
|
347
523
|
.filter((name) => ungradeableNames.includes(name));
|
|
348
|
-
const
|
|
349
|
-
let verdict = rawScore.verdict;
|
|
350
|
-
// Timeout takes precedence over inconclusive downgrade.
|
|
351
|
-
if (drive.timedOut) {
|
|
352
|
-
verdict = 'timeout';
|
|
353
|
-
} else if (rawScore.verdict === 'pass' && !anyCorrectAcrossAudit) {
|
|
354
|
-
verdict = 'inconclusive';
|
|
355
|
-
}
|
|
356
|
-
const score: AuditScore = { ...rawScore, verdict };
|
|
524
|
+
const score = evaluation.score;
|
|
357
525
|
|
|
358
526
|
// Persist the auditor transcript next to the report so a stuck/killed run
|
|
359
527
|
// can be inspected after the fact.
|
|
@@ -392,6 +560,8 @@ export async function runAudit(opts: RunAuditOptions): Promise<AuditScore> {
|
|
|
392
560
|
'imprint.audit.tool_count': toolCount,
|
|
393
561
|
'imprint.audit.verdict': score.verdict,
|
|
394
562
|
'imprint.audit.unverified_and_ungradeable_count': unverifiedAndUngradeable.length,
|
|
563
|
+
'imprint.audit.missing_tool_count': missingToolNames.length,
|
|
564
|
+
'imprint.audit.missing_parameter_count': missingParameters.length,
|
|
395
565
|
'imprint.audit.timed_out': drive.timedOut,
|
|
396
566
|
'imprint.audit.turns': drive.turns,
|
|
397
567
|
...(drive.totalCostUsd != null ? { 'imprint.audit.cost_usd': drive.totalCostUsd } : {}),
|
|
@@ -414,6 +584,11 @@ export async function runAudit(opts: RunAuditOptions): Promise<AuditScore> {
|
|
|
414
584
|
site: opts.site,
|
|
415
585
|
toolCount,
|
|
416
586
|
ungradeableTools: ungradeableNames,
|
|
587
|
+
/** Connected tools without an invocation record. A partial audit
|
|
588
|
+
* cannot pass merely because the auditor named an uncalled tool. */
|
|
589
|
+
missingTools: missingToolNames,
|
|
590
|
+
/** Advertised workflow parameters absent from the auditor's report. */
|
|
591
|
+
missingParameters,
|
|
417
592
|
/** Advertised parameters the auditor could not differentially test. */
|
|
418
593
|
untestableParams: untestableParamList,
|
|
419
594
|
/** Tools that shipped without live verification at compile time AND
|
|
@@ -445,6 +620,8 @@ export async function runAudit(opts: RunAuditOptions): Promise<AuditScore> {
|
|
|
445
620
|
transcriptPath,
|
|
446
621
|
costUsd: drive.totalCostUsd,
|
|
447
622
|
unverifiedAndUngradeable,
|
|
623
|
+
missingTools: missingToolNames,
|
|
624
|
+
missingParameters,
|
|
448
625
|
report: drive.report,
|
|
449
626
|
});
|
|
450
627
|
}
|
|
@@ -653,6 +830,7 @@ async function driveAuditWithCodex(opts: DriveAuditOptions): Promise<DriveAuditR
|
|
|
653
830
|
const serverName = `imprint-audit-${opts.site}`;
|
|
654
831
|
const bunPath = process.execPath;
|
|
655
832
|
const mcpArgs = ['run', CLI_PATH, 'mcp-server', opts.site];
|
|
833
|
+
const mcpEnv = buildAuditMcpEnvironment();
|
|
656
834
|
|
|
657
835
|
const unverifiedNote = buildUnverifiedParamNote(opts.unverifiedParams);
|
|
658
836
|
const initialPrompt = `<system_instructions>
|
|
@@ -685,9 +863,11 @@ ${buildAuditInitialPrompt(opts, unverifiedNote)}`;
|
|
|
685
863
|
'-c',
|
|
686
864
|
`mcp_servers.${serverName}.tool_timeout_sec=300`,
|
|
687
865
|
'-c',
|
|
688
|
-
`mcp_servers.${serverName}.env.
|
|
866
|
+
`mcp_servers.${serverName}.env.IMPRINT_HOME=${JSON.stringify(mcpEnv.IMPRINT_HOME)}`,
|
|
689
867
|
'-c',
|
|
690
|
-
`mcp_servers.${serverName}.env.
|
|
868
|
+
`mcp_servers.${serverName}.env.IMPRINT_AUDIT_PACING_MS=${JSON.stringify(mcpEnv.IMPRINT_AUDIT_PACING_MS)}`,
|
|
869
|
+
'-c',
|
|
870
|
+
`mcp_servers.${serverName}.env.IMPRINT_AUDIT_TOOL_DEADLINE_MS=${JSON.stringify(mcpEnv.IMPRINT_AUDIT_TOOL_DEADLINE_MS)}`,
|
|
691
871
|
'-c',
|
|
692
872
|
'shell_environment_policy.inherit=all',
|
|
693
873
|
'-',
|
|
@@ -701,8 +881,7 @@ ${buildAuditInitialPrompt(opts, unverifiedNote)}`;
|
|
|
701
881
|
cwd: REPO_ROOT,
|
|
702
882
|
env: {
|
|
703
883
|
...process.env,
|
|
704
|
-
|
|
705
|
-
IMPRINT_AUDIT_TOOL_DEADLINE_MS: '120000',
|
|
884
|
+
...mcpEnv,
|
|
706
885
|
},
|
|
707
886
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
708
887
|
});
|
|
@@ -1209,6 +1388,8 @@ function printSummary(
|
|
|
1209
1388
|
transcriptPath?: string;
|
|
1210
1389
|
costUsd?: number | null;
|
|
1211
1390
|
unverifiedAndUngradeable: string[];
|
|
1391
|
+
missingTools: string[];
|
|
1392
|
+
missingParameters: MissingAuditedParameter[];
|
|
1212
1393
|
report: AuditReport;
|
|
1213
1394
|
},
|
|
1214
1395
|
): void {
|
|
@@ -1255,12 +1436,30 @@ function printSummary(
|
|
|
1255
1436
|
`[imprint] ${extra.unverifiedAndUngradeable.length} tool(s) flying blind (no live verification at compile, no graded calls at audit): ${extra.unverifiedAndUngradeable.join(', ')}`,
|
|
1256
1437
|
);
|
|
1257
1438
|
}
|
|
1439
|
+
if (extra.missingTools.length > 0) {
|
|
1440
|
+
console.log(
|
|
1441
|
+
`[imprint] ${extra.missingTools.length} connected tool(s) have no invocation attempt in the auditor report: ${extra.missingTools.join(', ')}`,
|
|
1442
|
+
);
|
|
1443
|
+
}
|
|
1444
|
+
if (extra.missingParameters.length > 0) {
|
|
1445
|
+
console.log(
|
|
1446
|
+
`[imprint] ${extra.missingParameters.length} advertised parameter(s) missing from the auditor report: ${extra.missingParameters.map((parameter) => `${parameter.tool}.${parameter.name}`).join(', ')}`,
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1258
1449
|
if (score.verdict === 'timeout') {
|
|
1259
1450
|
console.log(
|
|
1260
1451
|
`[imprint] audit was killed at the ${formatDeadline(extra.timeoutMs)} deadline before finishing — partial results only. Re-run with a longer --timeout, or inspect the transcript to see where it stalled.`,
|
|
1261
1452
|
);
|
|
1262
1453
|
} else if (score.verdict === 'inconclusive') {
|
|
1263
|
-
if (extra.
|
|
1454
|
+
if (extra.missingTools.length > 0) {
|
|
1455
|
+
console.log(
|
|
1456
|
+
'[imprint] verdict downgraded to inconclusive because the auditor did not record an invocation attempt for every connected tool.',
|
|
1457
|
+
);
|
|
1458
|
+
} else if (extra.missingParameters.length > 0) {
|
|
1459
|
+
console.log(
|
|
1460
|
+
'[imprint] verdict downgraded to inconclusive because the auditor did not report every advertised parameter.',
|
|
1461
|
+
);
|
|
1462
|
+
} else if (extra.unverifiedAndUngradeable.length > 0) {
|
|
1264
1463
|
console.log(
|
|
1265
1464
|
'[imprint] verdict downgraded to inconclusive because at least one tool has zero live signal anywhere.',
|
|
1266
1465
|
);
|