jev-agent-tools 0.2.0 → 0.3.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/CHANGELOG.md +37 -1
- package/CONTRIBUTING.md +3 -0
- package/README.md +22 -14
- package/SECURITY.md +17 -1
- package/dist/adapters/ask-files.js +11 -2
- package/dist/adapters/ask-proof.js +63 -7
- package/dist/adapters/command.js +82 -29
- package/dist/adapters/docs.js +30 -10
- package/dist/adapters/evidence-context.js +119 -0
- package/dist/adapters/files.js +141 -16
- package/dist/adapters/find.js +34 -6
- package/dist/adapters/git-base.js +7 -1
- package/dist/adapters/git.js +51 -7
- package/dist/adapters/locate-file.js +47 -9
- package/dist/adapters/private-storage.js +14 -6
- package/dist/adapters/risk-callers.js +3 -0
- package/dist/adapters/shell.js +23 -7
- package/dist/adapters/test-inventory.js +10 -2
- package/dist/configuration.js +17 -7
- package/dist/constants.js +26 -5
- package/dist/core/ask-references.js +193 -109
- package/dist/core/asks.js +78 -7
- package/dist/core/locate.js +8 -8
- package/dist/core/output.js +17 -0
- package/dist/core/result-report.js +302 -0
- package/dist/core/secret-path.js +34 -0
- package/dist/core/state.js +8 -1
- package/dist/core/units.js +1 -1
- package/dist/jev/client.js +34 -12
- package/dist/mcp/protocol.js +50 -27
- package/dist/mcp/tools.js +20 -7
- package/dist/render.js +72 -0
- package/dist/report-schema.js +1356 -0
- package/dist/result-types.js +1 -0
- package/dist/texts/ask-files.js +3 -1
- package/dist/texts/ask.js +3 -1
- package/dist/texts/check-diff.js +7 -4
- package/dist/texts/find.js +7 -2
- package/dist/texts/guide.js +3 -16
- package/dist/texts/instructions.js +72 -0
- package/dist/texts/locate.js +7 -2
- package/dist/texts/select-tests.js +3 -1
- package/dist/tools/ask-files.js +248 -15
- package/dist/tools/ask.js +523 -62
- package/dist/tools/check-diff.js +222 -30
- package/dist/tools/docs-check.js +122 -13
- package/dist/tools/find.js +320 -27
- package/dist/tools/locate.js +317 -18
- package/dist/tools/review-report.js +230 -0
- package/dist/tools/select-tests.js +273 -19
- package/dist/tools/spec-check.js +119 -22
- package/docs/adr/0001-strict-typescript-pure-core-offline-tests.md +3 -3
- package/docs/agent-instructions.md +59 -30
- package/docs/design.md +13 -1
- package/docs/mcp.md +8 -6
- package/docs/tools/jev_ask.md +8 -5
- package/docs/tools/jev_ask_files.md +2 -1
- package/docs/tools/jev_check_diff.md +4 -1
- package/docs/tools/jev_find_files.md +2 -1
- package/docs/tools/jev_locate_in_file.md +5 -0
- package/docs/tools/jev_select_tests.md +4 -1
- package/package.json +1 -1
- package/rules/jev-ask.md +22 -1
- package/server.json +2 -2
- package/src/adapters/ask-files.ts +11 -3
- package/src/adapters/ask-proof.ts +69 -11
- package/src/adapters/command.ts +96 -33
- package/src/adapters/docs.ts +33 -14
- package/src/adapters/evidence-context.ts +169 -0
- package/src/adapters/files.ts +146 -16
- package/src/adapters/find.ts +37 -7
- package/src/adapters/git-base.ts +7 -1
- package/src/adapters/git.ts +61 -8
- package/src/adapters/locate-file.ts +51 -9
- package/src/adapters/private-storage.ts +17 -5
- package/src/adapters/risk-callers.ts +3 -0
- package/src/adapters/shell.ts +23 -7
- package/src/adapters/test-inventory.ts +12 -4
- package/src/configuration.ts +16 -2
- package/src/constants.ts +26 -5
- package/src/core/ask-references.ts +262 -146
- package/src/core/asks.ts +79 -7
- package/src/core/import-boundaries.ts +8 -3
- package/src/core/locate.ts +8 -5
- package/src/core/output.ts +34 -0
- package/src/core/result-report.ts +410 -0
- package/src/core/secret-path.ts +37 -0
- package/src/core/state.ts +8 -1
- package/src/core/units.ts +3 -2
- package/src/index.ts +3 -0
- package/src/jev/client.ts +54 -16
- package/src/jev/types.ts +18 -3
- package/src/mcp/protocol.ts +91 -41
- package/src/mcp/tools.ts +26 -13
- package/src/render.ts +109 -0
- package/src/report-schema.ts +1380 -0
- package/src/result-types.ts +234 -0
- package/src/result.ts +4 -1
- package/src/runtime.ts +6 -0
- package/src/texts/ask-files.ts +4 -1
- package/src/texts/ask.ts +8 -1
- package/src/texts/check-diff.ts +7 -4
- package/src/texts/find.ts +8 -2
- package/src/texts/guide.ts +8 -16
- package/src/texts/instructions.ts +98 -0
- package/src/texts/locate.ts +8 -2
- package/src/texts/run-end.ts +2 -2
- package/src/texts/select-tests.ts +4 -1
- package/src/tools/ask-files.ts +309 -14
- package/src/tools/ask.ts +700 -77
- package/src/tools/check-diff.ts +331 -28
- package/src/tools/docs-check.ts +241 -39
- package/src/tools/find.ts +386 -29
- package/src/tools/locate.ts +384 -19
- package/src/tools/review-report.ts +308 -0
- package/src/tools/select-tests.ts +479 -21
- package/src/tools/spec-check.ts +193 -19
package/src/tools/ask-files.ts
CHANGED
|
@@ -3,9 +3,13 @@ import { resolve } from "node:path";
|
|
|
3
3
|
import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
import { type Static, Type } from "@sinclair/typebox";
|
|
5
5
|
import { collectAskFiles } from "../adapters/ask-files.ts";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
resolveEvidenceContext,
|
|
8
|
+
withEvidenceContext,
|
|
9
|
+
} from "../adapters/evidence-context.ts";
|
|
7
10
|
import { shareGitInventory } from "../adapters/git-inventory.ts";
|
|
8
11
|
import { hostUsage } from "../adapters/usage.ts";
|
|
12
|
+
import { STATE_MAX_CHARS } from "../constants.ts";
|
|
9
13
|
import { compileAsks, readAsks, reverseQuestions } from "../core/asks.ts";
|
|
10
14
|
import { checkIntegrity } from "../core/integrity.ts";
|
|
11
15
|
import type {
|
|
@@ -15,10 +19,22 @@ import type {
|
|
|
15
19
|
EnvelopeInput,
|
|
16
20
|
} from "../core/output.ts";
|
|
17
21
|
import { buildEnvelope } from "../core/output.ts";
|
|
22
|
+
import {
|
|
23
|
+
type Action,
|
|
24
|
+
answerItemFromInput,
|
|
25
|
+
buildResultReport,
|
|
26
|
+
type Cause,
|
|
27
|
+
contextFromEvidence,
|
|
28
|
+
type Diagnostic,
|
|
29
|
+
type Item,
|
|
30
|
+
known,
|
|
31
|
+
type ResultReportV1,
|
|
32
|
+
unknown,
|
|
33
|
+
} from "../core/result-report.ts";
|
|
18
34
|
import { interpolate } from "../describe.ts";
|
|
19
35
|
import type { GuideContext } from "../guide.ts";
|
|
20
36
|
import type { Answer, Judgment, JudgmentMetadata } from "../jev/types.ts";
|
|
21
|
-
import {
|
|
37
|
+
import { renderResultReport } from "../render.ts";
|
|
22
38
|
import type { ToolDependencies } from "../runtime.ts";
|
|
23
39
|
import { ASK_FILES_DESCRIPTION } from "../texts/ask-files.ts";
|
|
24
40
|
import { NOT_CONFIGURED } from "../texts/configuration.ts";
|
|
@@ -26,6 +42,7 @@ import { asksParameter } from "./ask-schema.ts";
|
|
|
26
42
|
|
|
27
43
|
export const askFilesParameters = Type.Object(
|
|
28
44
|
{
|
|
45
|
+
root: Type.Optional(Type.String()),
|
|
29
46
|
paths: Type.Array(Type.String({ minLength: 1 }), { minItems: 1 }),
|
|
30
47
|
asks: asksParameter("files"),
|
|
31
48
|
max_calls: Type.Optional(Type.Integer({ minimum: 0 })),
|
|
@@ -42,6 +59,7 @@ export interface AskFilesDetails {
|
|
|
42
59
|
files: FileJudgment[];
|
|
43
60
|
skipped: string[];
|
|
44
61
|
envelope: Envelope;
|
|
62
|
+
result: ResultReportV1;
|
|
45
63
|
}
|
|
46
64
|
export function createAskFilesTool(dependencies: ToolDependencies) {
|
|
47
65
|
const { host, runtime, exec: execute } = dependencies;
|
|
@@ -68,9 +86,74 @@ export function createAskFilesTool(dependencies: ToolDependencies) {
|
|
|
68
86
|
ctx: { cwd: string } & GuideContext,
|
|
69
87
|
) {
|
|
70
88
|
const client = dependencies.client;
|
|
71
|
-
const
|
|
89
|
+
const evidence = await resolveEvidenceContext(ctx.cwd, args.root, {
|
|
90
|
+
exec: execute,
|
|
91
|
+
signal,
|
|
92
|
+
origin: dependencies.evidenceOrigin,
|
|
93
|
+
});
|
|
94
|
+
const evidenceContext = evidence.context;
|
|
95
|
+
const cwd = evidence.ok ? evidence.cwd : evidenceContext.authority.path;
|
|
72
96
|
const started = performance.now();
|
|
73
97
|
const exec = shareGitInventory(execute);
|
|
98
|
+
const plan = compileAsks(args.asks, { surface: "files" });
|
|
99
|
+
let refusalCause: Cause = "invalid_arguments";
|
|
100
|
+
let collectedPaths: string[] | undefined;
|
|
101
|
+
let costKnown = true;
|
|
102
|
+
const reportItems: Item[] = [];
|
|
103
|
+
const diagnostics: Diagnostic[] = [];
|
|
104
|
+
const actions: Action[] = [];
|
|
105
|
+
const auxiliary = {
|
|
106
|
+
controls: { fresh: 0, cache: 0, notJudged: 0, static: 0 },
|
|
107
|
+
passages: { fresh: 0, cache: 0, notJudged: 0 },
|
|
108
|
+
};
|
|
109
|
+
const diagnose = (
|
|
110
|
+
cause: Cause,
|
|
111
|
+
fact: string,
|
|
112
|
+
scope: Diagnostic["scope"],
|
|
113
|
+
target?: string,
|
|
114
|
+
) => {
|
|
115
|
+
const id = `diagnostic:${diagnostics.length}`,
|
|
116
|
+
actionId = `action:${actions.length}`;
|
|
117
|
+
actions.push({
|
|
118
|
+
id: actionId,
|
|
119
|
+
code:
|
|
120
|
+
cause === "invalid_root"
|
|
121
|
+
? "correct_context"
|
|
122
|
+
: cause === "not_configured"
|
|
123
|
+
? "configure_client"
|
|
124
|
+
: "inspect_native",
|
|
125
|
+
target:
|
|
126
|
+
target === undefined
|
|
127
|
+
? unknown("target not established")
|
|
128
|
+
: known(target),
|
|
129
|
+
scope,
|
|
130
|
+
condition:
|
|
131
|
+
"Only after correcting context or supplying materially new evidence",
|
|
132
|
+
instruction:
|
|
133
|
+
"Read the admitted files natively; do not repeat the unchanged Jev call.",
|
|
134
|
+
repeatUnchanged: false,
|
|
135
|
+
});
|
|
136
|
+
diagnostics.push({
|
|
137
|
+
id,
|
|
138
|
+
cause,
|
|
139
|
+
fact,
|
|
140
|
+
target:
|
|
141
|
+
target === undefined
|
|
142
|
+
? unknown("target not established")
|
|
143
|
+
: known(target),
|
|
144
|
+
origin:
|
|
145
|
+
cause === "call_budget" || cause === "session_budget"
|
|
146
|
+
? "budget"
|
|
147
|
+
: "collection",
|
|
148
|
+
scope,
|
|
149
|
+
effect: "blocking",
|
|
150
|
+
material: true,
|
|
151
|
+
omittedMembers: [],
|
|
152
|
+
memberCount: known(0),
|
|
153
|
+
actionIds: [actionId],
|
|
154
|
+
});
|
|
155
|
+
return { diagnosticIds: [id], actionIds: [actionId] };
|
|
156
|
+
};
|
|
74
157
|
const totals = {
|
|
75
158
|
calls: 0,
|
|
76
159
|
questions: 0,
|
|
@@ -88,31 +171,156 @@ export function createAskFilesTool(dependencies: ToolDependencies) {
|
|
|
88
171
|
});
|
|
89
172
|
runtime.session.record(envelope);
|
|
90
173
|
runtime.guide.deliver(ctx);
|
|
174
|
+
if (!reportItems.length && !diagnostics.length)
|
|
175
|
+
diagnose(
|
|
176
|
+
input.refusal ? refusalCause : "collection_empty",
|
|
177
|
+
input.refusal ?? "No file-question results collected",
|
|
178
|
+
{ kind: "call" },
|
|
179
|
+
);
|
|
180
|
+
if (!reportItems.length && collectedPaths && plan.ok)
|
|
181
|
+
for (const path of collectedPaths)
|
|
182
|
+
for (const reading of plan.readings)
|
|
183
|
+
reportItems.push({
|
|
184
|
+
id: `${path}:${reading.id}`,
|
|
185
|
+
kind: "file_question",
|
|
186
|
+
label: `${path} ${reading.label}`,
|
|
187
|
+
groupId: `${path}:group:${plan.groups.findIndex((group) => group.includes(reading.id))}`,
|
|
188
|
+
evidence: [
|
|
189
|
+
{
|
|
190
|
+
target: path,
|
|
191
|
+
canonicalPath: known(resolve(cwd, path)),
|
|
192
|
+
aliases: [],
|
|
193
|
+
side: "current",
|
|
194
|
+
revision: unknown("working tree evidence"),
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
diagnosticIds: diagnostics.map((diagnostic) => diagnostic.id),
|
|
198
|
+
actionIds: actions.map((action) => action.id),
|
|
199
|
+
treatment: "not_judged",
|
|
200
|
+
source: "none",
|
|
201
|
+
});
|
|
202
|
+
for (const limitation of input.limitations ?? []) {
|
|
203
|
+
diagnose(
|
|
204
|
+
"evidence_limit",
|
|
205
|
+
limitation.fact,
|
|
206
|
+
{ kind: "call" },
|
|
207
|
+
limitation.path,
|
|
208
|
+
);
|
|
209
|
+
const diagnostic = diagnostics.at(-1);
|
|
210
|
+
if (diagnostic) diagnostic.effect = "reservation";
|
|
211
|
+
}
|
|
212
|
+
const report = buildResultReport({
|
|
213
|
+
tool: "jev_ask_files",
|
|
214
|
+
context: contextFromEvidence(evidenceContext, {
|
|
215
|
+
inventories: collectedPaths
|
|
216
|
+
? [
|
|
217
|
+
{
|
|
218
|
+
id: "files",
|
|
219
|
+
kind: "repository",
|
|
220
|
+
rules: [
|
|
221
|
+
"Requested paths expanded with admission and pruning",
|
|
222
|
+
],
|
|
223
|
+
restrictions: args.paths,
|
|
224
|
+
discovered: unknown(
|
|
225
|
+
"collector does not expose pre-pruning candidate count",
|
|
226
|
+
),
|
|
227
|
+
considered: known(collectedPaths.length),
|
|
228
|
+
scopeRestricted: true,
|
|
229
|
+
criteria: [],
|
|
230
|
+
},
|
|
231
|
+
]
|
|
232
|
+
: [],
|
|
233
|
+
}),
|
|
234
|
+
items: reportItems,
|
|
235
|
+
diagnostics,
|
|
236
|
+
actions,
|
|
237
|
+
metrics: {
|
|
238
|
+
...totals,
|
|
239
|
+
costUsd: costKnown && collectedPaths ? totals.costUsd : undefined,
|
|
240
|
+
elapsedMs: performance.now() - started,
|
|
241
|
+
},
|
|
242
|
+
auxiliary,
|
|
243
|
+
total:
|
|
244
|
+
collectedPaths && plan.ok
|
|
245
|
+
? known(collectedPaths.length * plan.readings.length)
|
|
246
|
+
: unknown("file-question inventory not collected"),
|
|
247
|
+
refused: !!input.refusal && refusalCause !== "not_configured",
|
|
248
|
+
});
|
|
91
249
|
const usage = hostUsage(host.isOmp, {
|
|
92
250
|
inputTokens: totals.inputTokens,
|
|
93
251
|
costUsd: totals.costUsd,
|
|
94
252
|
});
|
|
95
253
|
return {
|
|
96
|
-
content: [
|
|
97
|
-
|
|
254
|
+
content: [
|
|
255
|
+
{
|
|
256
|
+
type: "text" as const,
|
|
257
|
+
text: renderResultReport(report, { details: envelope }),
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
details: {
|
|
261
|
+
files: records,
|
|
262
|
+
skipped,
|
|
263
|
+
envelope,
|
|
264
|
+
evidenceContext,
|
|
265
|
+
result: report,
|
|
266
|
+
},
|
|
98
267
|
...usage,
|
|
99
268
|
};
|
|
100
269
|
};
|
|
101
|
-
if (!
|
|
102
|
-
|
|
270
|
+
if (!evidence.ok) {
|
|
271
|
+
refusalCause = evidence.cause ?? "invalid_root";
|
|
272
|
+
return finish({ refusal: evidence.error });
|
|
273
|
+
}
|
|
103
274
|
if (!plan.ok) return finish({ refusal: plan.error });
|
|
275
|
+
if (!client) {
|
|
276
|
+
refusalCause = "not_configured";
|
|
277
|
+
return finish({ refusal: NOT_CONFIGURED });
|
|
278
|
+
}
|
|
104
279
|
const collected = await collectAskFiles(cwd, args.paths, signal, exec);
|
|
105
|
-
if (!collected.ok)
|
|
280
|
+
if (!collected.ok) {
|
|
281
|
+
refusalCause = collected.cause ?? "file_unavailable";
|
|
282
|
+
return finish({ refusal: collected.error });
|
|
283
|
+
}
|
|
284
|
+
collectedPaths = collected.files.map((file) => file.path);
|
|
106
285
|
skipped = collected.skipped;
|
|
286
|
+
for (const skippedPath of skipped)
|
|
287
|
+
diagnose(
|
|
288
|
+
collected.secret.includes(skippedPath)
|
|
289
|
+
? "secret_pattern"
|
|
290
|
+
: "collection_omitted",
|
|
291
|
+
skippedPath,
|
|
292
|
+
{ kind: "inventory", inventoryIds: ["files"] },
|
|
293
|
+
);
|
|
107
294
|
if (!collected.files.length && skipped.length)
|
|
108
295
|
return finish({
|
|
109
296
|
refusal: `No readable evidence: ${skipped.join("; ")}`,
|
|
110
297
|
});
|
|
298
|
+
const states = collected.files.map((file) => ({
|
|
299
|
+
file,
|
|
300
|
+
state: withEvidenceContext(
|
|
301
|
+
{ path: file.path, content: file.content },
|
|
302
|
+
evidenceContext,
|
|
303
|
+
),
|
|
304
|
+
}));
|
|
305
|
+
if (
|
|
306
|
+
states.some(
|
|
307
|
+
({ state }) => JSON.stringify(state).length > STATE_MAX_CHARS,
|
|
308
|
+
)
|
|
309
|
+
) {
|
|
310
|
+
refusalCause = "evidence_too_large";
|
|
311
|
+
return finish({
|
|
312
|
+
refusal: `required evidence exceeds STATE_MAX_CHARS=${STATE_MAX_CHARS}`,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
111
315
|
let sent = 0;
|
|
112
316
|
let budget: BudgetRefusal | undefined;
|
|
113
317
|
const options = {
|
|
114
318
|
signal,
|
|
115
319
|
...runtime.session.requestGate(),
|
|
320
|
+
admissionCause: () =>
|
|
321
|
+
budget?.kind === "session"
|
|
322
|
+
? ("session_budget" as const)
|
|
323
|
+
: ("call_budget" as const),
|
|
116
324
|
beforeRequest: (count: number) => {
|
|
117
325
|
if (args.max_calls !== undefined && sent >= args.max_calls) {
|
|
118
326
|
budget = {
|
|
@@ -139,17 +347,17 @@ export function createAskFilesTool(dependencies: ToolDependencies) {
|
|
|
139
347
|
totals.cacheRequests += result.cacheRequests ?? 0;
|
|
140
348
|
totals.inputTokens += result.usage?.inputTokens ?? 0;
|
|
141
349
|
totals.costUsd += result.usage?.costUsd ?? 0;
|
|
350
|
+
if (!result.usage && result.calls !== 0) costKnown = false;
|
|
142
351
|
};
|
|
143
352
|
const rows = await Promise.all(
|
|
144
|
-
|
|
145
|
-
const state = { path: file.path, content: file.content };
|
|
353
|
+
states.map(async ({ file, state }) => {
|
|
146
354
|
const integrity = checkIntegrity(state, plan.asks, [
|
|
147
355
|
{
|
|
148
356
|
...file.identity,
|
|
149
|
-
insertedPath: resolve(cwd,
|
|
150
|
-
content:
|
|
357
|
+
insertedPath: resolve(cwd, file.path),
|
|
358
|
+
content: file.content,
|
|
151
359
|
insertedSha256: createHash("sha256")
|
|
152
|
-
.update(
|
|
360
|
+
.update(file.content)
|
|
153
361
|
.digest("hex"),
|
|
154
362
|
},
|
|
155
363
|
]);
|
|
@@ -191,6 +399,93 @@ export function createAskFilesTool(dependencies: ToolDependencies) {
|
|
|
191
399
|
const unchecked: string[] = [];
|
|
192
400
|
const unjudged: NonNullable<EnvelopeInput["unjudged"]>[number][] = [];
|
|
193
401
|
for (const row of rows) {
|
|
402
|
+
const readings = plan.readings;
|
|
403
|
+
for (const [index, reading] of readings.entries()) {
|
|
404
|
+
const groupId = `${row.file.path}:group:${plan.groups.findIndex((group) => group.includes(reading.id))}`;
|
|
405
|
+
const common = {
|
|
406
|
+
id: `${row.file.path}:${reading.id}`,
|
|
407
|
+
kind: "file_question" as const,
|
|
408
|
+
label: `${row.file.path} ${reading.label}`,
|
|
409
|
+
groupId,
|
|
410
|
+
evidence: [
|
|
411
|
+
{
|
|
412
|
+
target: row.file.path,
|
|
413
|
+
canonicalPath: known(resolve(cwd, row.file.path)),
|
|
414
|
+
aliases: [],
|
|
415
|
+
side: "current" as const,
|
|
416
|
+
revision: unknown("working tree evidence"),
|
|
417
|
+
},
|
|
418
|
+
],
|
|
419
|
+
diagnosticIds: [] as string[],
|
|
420
|
+
actionIds: [] as string[],
|
|
421
|
+
};
|
|
422
|
+
const answer = row.answers[index];
|
|
423
|
+
if (
|
|
424
|
+
answer &&
|
|
425
|
+
!answer.unjudged &&
|
|
426
|
+
(answer.source || answer.answer?.source)
|
|
427
|
+
)
|
|
428
|
+
reportItems.push(
|
|
429
|
+
answerItemFromInput(
|
|
430
|
+
common,
|
|
431
|
+
row.integrity.controls.length
|
|
432
|
+
? {
|
|
433
|
+
...answer,
|
|
434
|
+
band: "unsure",
|
|
435
|
+
reason: row.integrity.controls
|
|
436
|
+
.map((control) => control.fact)
|
|
437
|
+
.join("; "),
|
|
438
|
+
}
|
|
439
|
+
: answer,
|
|
440
|
+
),
|
|
441
|
+
);
|
|
442
|
+
else {
|
|
443
|
+
const raw = row.initial.ok
|
|
444
|
+
? row.initial.answers[reading.id]
|
|
445
|
+
: undefined;
|
|
446
|
+
const cause =
|
|
447
|
+
raw?.type === "unjudged" ? raw.cause : row.initial.failureCause;
|
|
448
|
+
const links = diagnose(
|
|
449
|
+
cause ??
|
|
450
|
+
(budget
|
|
451
|
+
? budget.kind === "session"
|
|
452
|
+
? "session_budget"
|
|
453
|
+
: "call_budget"
|
|
454
|
+
: "control_failure"),
|
|
455
|
+
answer?.reason ??
|
|
456
|
+
(row.initial.ok
|
|
457
|
+
? "Required group incomplete or response provenance not established"
|
|
458
|
+
: row.initial.error),
|
|
459
|
+
{ kind: "group", groupIds: [groupId] },
|
|
460
|
+
row.file.path,
|
|
461
|
+
);
|
|
462
|
+
reportItems.push({
|
|
463
|
+
...common,
|
|
464
|
+
...links,
|
|
465
|
+
treatment: "not_judged",
|
|
466
|
+
source: "none",
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
for (const id of [
|
|
470
|
+
reading.twin,
|
|
471
|
+
...Object.values(reading.controls ?? {}),
|
|
472
|
+
].filter((id): id is string => !!id)) {
|
|
473
|
+
const control = row.initial.ok
|
|
474
|
+
? row.initial.answers[id]
|
|
475
|
+
: undefined;
|
|
476
|
+
if (control && control.type !== "unjudged" && control.source)
|
|
477
|
+
auxiliary.controls[control.source]++;
|
|
478
|
+
else auxiliary.controls.notJudged++;
|
|
479
|
+
}
|
|
480
|
+
const reverse = row.reversed?.ok
|
|
481
|
+
? row.reversed.answers[reading.id]
|
|
482
|
+
: undefined;
|
|
483
|
+
if (row.reversed) {
|
|
484
|
+
if (reverse && reverse.type !== "unjudged" && reverse.source)
|
|
485
|
+
auxiliary.controls[reverse.source]++;
|
|
486
|
+
else auxiliary.controls.notJudged++;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
194
489
|
records.push({
|
|
195
490
|
path: row.file.path,
|
|
196
491
|
initial: row.initial,
|
|
@@ -201,7 +496,7 @@ export function createAskFilesTool(dependencies: ToolDependencies) {
|
|
|
201
496
|
unjudged.push({
|
|
202
497
|
label: row.file.path,
|
|
203
498
|
reason: row.initial.error,
|
|
204
|
-
next: "read the file or
|
|
499
|
+
next: "read the supplied file natively; a new Jev call needs materially changed evidence or recovered service",
|
|
205
500
|
});
|
|
206
501
|
continue;
|
|
207
502
|
}
|