pi-jev-guard 0.7.1 → 0.7.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 +6 -2
- package/extensions/index.ts +66 -1
- package/package.json +1 -1
- package/src/grounding.ts +35 -3
- package/src/tools.ts +1 -0
- package/src/verification-tool.ts +1 -0
package/README.md
CHANGED
|
@@ -148,7 +148,9 @@ Non blocca mai; `/jev output` mostra l'ultimo verdetto.
|
|
|
148
148
|
|
|
149
149
|
Sempre in `automatic`, il **grounding** (opt-in, default spento) confronta le
|
|
150
150
|
affermazioni sulla sessione — "ho letto il file", "i test passano", "ho
|
|
151
|
-
eseguito X" — con un registro evidenza costruito dai
|
|
151
|
+
eseguito X", "il guard riporta X" — con un registro evidenza costruito dai
|
|
152
|
+
`tool_result` e dai fatti generati dal guard (footer di verifica, run
|
|
153
|
+
`jev_verify`)
|
|
152
154
|
(comandi, test, letture, modifiche; redatto, max 30 voci, solo sessione
|
|
153
155
|
corrente). Due domande Jev strette: contraddizione con l'evidenza e
|
|
154
156
|
affermazione non supportata. Senza evidenza non si giudica: "senza
|
|
@@ -165,7 +167,9 @@ Il grounding è probabilistico; per **compilazione, lint e test** serve una
|
|
|
165
167
|
prova deterministica. La verifica progetto conserva, solo nella sessione,
|
|
166
168
|
`edit`/`write` riusciti e gli esiti osservati dei check. Il footer viene
|
|
167
169
|
generato dall'estensione, non dal modello: un test non eseguito non può
|
|
168
|
-
diventare “test passati”.
|
|
170
|
+
diventare “test passati”. Un report di “verifica” scritto dal modello non ha
|
|
171
|
+
valore: il footer autorevole è solo quello del guard (marcato `generata dal
|
|
172
|
+
guard, non dal modello`) e una guideline ai tool scoraggia le imitazioni.
|
|
169
173
|
|
|
170
174
|
#### Nuovi progetti: zero manifest locale
|
|
171
175
|
|
package/extensions/index.ts
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
OUTPUT_QUESTIONS,
|
|
33
33
|
buildOutputState,
|
|
34
34
|
createVerdictCache,
|
|
35
|
+
elideText,
|
|
35
36
|
evaluateOutput,
|
|
36
37
|
outputKey,
|
|
37
38
|
toolResultText,
|
|
@@ -52,6 +53,7 @@ import {
|
|
|
52
53
|
decideGroundingAction,
|
|
53
54
|
evaluateGrounding,
|
|
54
55
|
groundingKey,
|
|
56
|
+
guardEvidenceEntry,
|
|
55
57
|
recordEvidence,
|
|
56
58
|
recordToolResult,
|
|
57
59
|
parseExitCode,
|
|
@@ -73,6 +75,7 @@ import {
|
|
|
73
75
|
selectVerificationChecks,
|
|
74
76
|
trustVerificationPolicy,
|
|
75
77
|
trustedVerificationPolicy,
|
|
78
|
+
verificationNotice,
|
|
76
79
|
type VerificationManifestTrust,
|
|
77
80
|
type VerificationStatus,
|
|
78
81
|
} from "../src/verification.ts";
|
|
@@ -224,7 +227,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
224
227
|
* Esegue SOLO check estratti dalla policy acquisita (locale, globale o
|
|
225
228
|
* profilo integrato). Serve sia al tool del modello sia a /jev verify.
|
|
226
229
|
*/
|
|
227
|
-
async function
|
|
230
|
+
async function executeProjectVerification(args: {
|
|
228
231
|
cwd: string;
|
|
229
232
|
selection: string | undefined;
|
|
230
233
|
signal?: AbortSignal;
|
|
@@ -273,6 +276,27 @@ export default function (pi: ExtensionAPI) {
|
|
|
273
276
|
};
|
|
274
277
|
}
|
|
275
278
|
|
|
279
|
+
/** Wrapper audit: ogni run (tool o comando) è evidenza per il grounding. */
|
|
280
|
+
async function runProjectVerification(args: {
|
|
281
|
+
cwd: string;
|
|
282
|
+
selection: string | undefined;
|
|
283
|
+
signal?: AbortSignal;
|
|
284
|
+
trusted: boolean;
|
|
285
|
+
}): Promise<VerificationToolRunResult> {
|
|
286
|
+
const outcome = await executeProjectVerification(args);
|
|
287
|
+
recordGuardFact({
|
|
288
|
+
tool: "jev_verify",
|
|
289
|
+
summary: `jev_verify: ${args.selection ?? "recommended"} → ${
|
|
290
|
+
outcome.results.length > 0
|
|
291
|
+
? outcome.results.map((r) => `${r.id}:${r.ok ? "pass" : "fail"}`).join(", ")
|
|
292
|
+
: "nessun check eseguito"
|
|
293
|
+
}`,
|
|
294
|
+
ok: outcome.results.length > 0 && outcome.results.every((r) => r.ok),
|
|
295
|
+
excerpt: outcome.message,
|
|
296
|
+
});
|
|
297
|
+
return outcome;
|
|
298
|
+
}
|
|
299
|
+
|
|
276
300
|
/** Provider live corrente dal registry (sempre fresco, mai snapshot). */
|
|
277
301
|
function liveUpstreamProvider(
|
|
278
302
|
registry: ModelRegistry,
|
|
@@ -860,6 +884,39 @@ export default function (pi: ExtensionAPI) {
|
|
|
860
884
|
}
|
|
861
885
|
}
|
|
862
886
|
|
|
887
|
+
/**
|
|
888
|
+
* I fatti generati dal guard (footer di verifica, run jev_verify) sono
|
|
889
|
+
* evidenza di prima classe per il grounding: senza questo, citare "il guard
|
|
890
|
+
* riporta X" risulterebbe sempre un'affermazione non supportata.
|
|
891
|
+
*/
|
|
892
|
+
function recordGuardFact(args: {
|
|
893
|
+
tool: "jev-guard" | "jev_verify";
|
|
894
|
+
summary: string;
|
|
895
|
+
ok: boolean;
|
|
896
|
+
excerpt?: string;
|
|
897
|
+
}): void {
|
|
898
|
+
try {
|
|
899
|
+
if (sessionMode !== "automatic" || !config.grounding.enabled) return;
|
|
900
|
+
const excerpt = args.excerpt?.trim()
|
|
901
|
+
? elideText(args.excerpt.trim(), Math.max(0, config.grounding.excerptChars))
|
|
902
|
+
: undefined;
|
|
903
|
+
const entry = guardEvidenceEntry({
|
|
904
|
+
tool: args.tool,
|
|
905
|
+
summary: args.summary,
|
|
906
|
+
ok: args.ok,
|
|
907
|
+
...(excerpt ? { excerpt } : {}),
|
|
908
|
+
seq: ++evidenceSeq,
|
|
909
|
+
at: Date.now(),
|
|
910
|
+
});
|
|
911
|
+
recordEvidence(evidenceLedger, entry, {
|
|
912
|
+
maxEntries: config.grounding.maxEntries,
|
|
913
|
+
invalidateTestsOnEdit: config.grounding.invalidateTestsOnEdit,
|
|
914
|
+
});
|
|
915
|
+
} catch {
|
|
916
|
+
// Mai rompere il flusso per il ledger.
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
|
|
863
920
|
function throttledGroundingError(error: unknown): void {
|
|
864
921
|
const now = Date.now();
|
|
865
922
|
if (now - lastGroundingErrorAt < 60_000) return;
|
|
@@ -996,6 +1053,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
996
1053
|
return async () => {
|
|
997
1054
|
const { status } = verificationSnapshot(cwd);
|
|
998
1055
|
if (status.changedFiles.length === 0) return { action: "publish" };
|
|
1056
|
+
// Il footer è un fatto del guard: entra nell'evidenza grounding,
|
|
1057
|
+
// così citarlo ("il guard riporta X") resta un claim verificabile.
|
|
1058
|
+
recordGuardFact({
|
|
1059
|
+
tool: "jev-guard",
|
|
1060
|
+
summary: `jev-guard: policy=${status.manifestSourceLabel ?? "sconosciuta"}; modifiche=${status.changedFiles.join(", ") || "nessuna"}; check=${status.checks.map((item) => `${item.check.id}:${item.state}`).join(", ") || "nessuno"}`,
|
|
1061
|
+
ok: status.allPassed,
|
|
1062
|
+
...(verificationNotice(status) ? { excerpt: verificationNotice(status) } : {}),
|
|
1063
|
+
});
|
|
999
1064
|
const decision = decideVerificationAction({
|
|
1000
1065
|
status,
|
|
1001
1066
|
mode,
|
package/package.json
CHANGED
package/src/grounding.ts
CHANGED
|
@@ -21,7 +21,7 @@ import type {
|
|
|
21
21
|
|
|
22
22
|
export type GroundingMode = "warn" | "repair" | "hold";
|
|
23
23
|
|
|
24
|
-
export type EvidenceKind = "command" | "test" | "read" | "modify";
|
|
24
|
+
export type EvidenceKind = "command" | "test" | "read" | "modify" | "verification";
|
|
25
25
|
|
|
26
26
|
export interface EvidenceEntry {
|
|
27
27
|
seq: number;
|
|
@@ -49,6 +49,38 @@ export function isTestCommand(command: string): boolean {
|
|
|
49
49
|
return TEST_COMMAND.test(command);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Prove di esito (test o verifica progetto): una modifica successiva le rende
|
|
54
|
+
* stale — non provano più lo stato attuale del codice.
|
|
55
|
+
*/
|
|
56
|
+
export function isOutcomeEvidence(kind: EvidenceKind): boolean {
|
|
57
|
+
return kind === "test" || kind === "verification";
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Fatto generato dal guard (footer di verifica, run jev_verify): entra
|
|
62
|
+
* nell'evidenza al pari dei tool_result, così le affermazioni
|
|
63
|
+
* "il guard riporta X" sono verificabili invece di sembrare inventate.
|
|
64
|
+
*/
|
|
65
|
+
export function guardEvidenceEntry(args: {
|
|
66
|
+
tool: "jev-guard" | "jev_verify";
|
|
67
|
+
summary: string;
|
|
68
|
+
ok: boolean;
|
|
69
|
+
seq: number;
|
|
70
|
+
at: number;
|
|
71
|
+
excerpt?: string;
|
|
72
|
+
}): EvidenceEntry {
|
|
73
|
+
return {
|
|
74
|
+
seq: args.seq,
|
|
75
|
+
at: args.at,
|
|
76
|
+
tool: args.tool,
|
|
77
|
+
kind: "verification",
|
|
78
|
+
summary: args.summary,
|
|
79
|
+
ok: args.ok,
|
|
80
|
+
...(args.excerpt ? { excerpt: args.excerpt } : {}),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
52
84
|
const EXIT_CODE = /Command exited with code (\d+)/;
|
|
53
85
|
|
|
54
86
|
/** Exit code dal testo d'errore pi ("Command exited with code N"). */
|
|
@@ -152,7 +184,7 @@ export function recordEvidence(
|
|
|
152
184
|
let invalidated = 0;
|
|
153
185
|
if (opts.invalidateTestsOnEdit && entry.kind === "modify" && entry.ok) {
|
|
154
186
|
for (const prior of ledger) {
|
|
155
|
-
if (prior.kind
|
|
187
|
+
if (isOutcomeEvidence(prior.kind) && !prior.stale && prior.seq < entry.seq) {
|
|
156
188
|
prior.stale = true;
|
|
157
189
|
invalidated++;
|
|
158
190
|
}
|
|
@@ -197,7 +229,7 @@ export function buildEvidenceDigest(
|
|
|
197
229
|
}
|
|
198
230
|
return {
|
|
199
231
|
entries,
|
|
200
|
-
hasStaleTests: recent.some((e) => e.kind
|
|
232
|
+
hasStaleTests: recent.some((e) => isOutcomeEvidence(e.kind) && e.stale),
|
|
201
233
|
};
|
|
202
234
|
}
|
|
203
235
|
|
package/src/tools.ts
CHANGED
|
@@ -20,6 +20,7 @@ export function registerJevTool(
|
|
|
20
20
|
"Use jev_validate when an independent targeted check is useful.",
|
|
21
21
|
"Do not describe review or unavailable as successful validation.",
|
|
22
22
|
"Jev validation does not replace compilation or tests.",
|
|
23
|
+
"Do not write your own verification-status sections in replies: the guard appends the only authoritative footer.",
|
|
23
24
|
],
|
|
24
25
|
parameters: Type.Object({
|
|
25
26
|
requirements: Type.String({ minLength: 1, maxLength: 16000 }),
|
package/src/verification-tool.ts
CHANGED
|
@@ -34,6 +34,7 @@ export function registerVerificationTool(
|
|
|
34
34
|
"After a successful edit/write, call jev_verify with check='recommended' when verification is enabled.",
|
|
35
35
|
"Use only this tool's declared check ids; never claim code compiles or tests pass without its observed result.",
|
|
36
36
|
"If a check fails, inspect its actual output, repair the code, then run the check again.",
|
|
37
|
+
"Never write your own verification report or imitate the guard footer in replies: the guard appends the only authoritative footer.",
|
|
37
38
|
],
|
|
38
39
|
parameters: Type.Object({
|
|
39
40
|
check: Type.Optional(
|