@vibe-agent-toolkit/agent-skills 0.1.39-rc.8 → 0.1.39
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/files-config.d.ts +61 -0
- package/dist/files-config.d.ts.map +1 -1
- package/dist/files-config.js +262 -6
- package/dist/files-config.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/plugin-distribution-layout.d.ts +70 -0
- package/dist/plugin-distribution-layout.d.ts.map +1 -0
- package/dist/plugin-distribution-layout.js +97 -0
- package/dist/plugin-distribution-layout.js.map +1 -0
- package/dist/skill-packager.d.ts +43 -1
- package/dist/skill-packager.d.ts.map +1 -1
- package/dist/skill-packager.js +131 -53
- package/dist/skill-packager.js.map +1 -1
- package/dist/skill-source/git-clone.d.ts +2 -2
- package/dist/skill-source/git-clone.d.ts.map +1 -1
- package/dist/skill-source/git-clone.js +33 -10
- package/dist/skill-source/git-clone.js.map +1 -1
- package/dist/skill-source/sources/url-source.d.ts.map +1 -1
- package/dist/skill-source/sources/url-source.js +23 -8
- package/dist/skill-source/sources/url-source.js.map +1 -1
- package/dist/skill-source/sources/workspace-source.d.ts.map +1 -1
- package/dist/skill-source/sources/workspace-source.js +16 -8
- package/dist/skill-source/sources/workspace-source.js.map +1 -1
- package/dist/skill-source/stage.js +6 -2
- package/dist/skill-source/stage.js.map +1 -1
- package/dist/skill-test/build-hook.d.ts +58 -0
- package/dist/skill-test/build-hook.d.ts.map +1 -0
- package/dist/skill-test/build-hook.js +63 -0
- package/dist/skill-test/build-hook.js.map +1 -0
- package/dist/skill-test/configure-writer.d.ts +19 -11
- package/dist/skill-test/configure-writer.d.ts.map +1 -1
- package/dist/skill-test/configure-writer.js +23 -15
- package/dist/skill-test/configure-writer.js.map +1 -1
- package/dist/skill-test/declared-env.d.ts +72 -0
- package/dist/skill-test/declared-env.d.ts.map +1 -0
- package/dist/skill-test/declared-env.js +85 -0
- package/dist/skill-test/declared-env.js.map +1 -0
- package/dist/skill-test/eval-inputs.d.ts +159 -0
- package/dist/skill-test/eval-inputs.d.ts.map +1 -0
- package/dist/skill-test/eval-inputs.js +158 -0
- package/dist/skill-test/eval-inputs.js.map +1 -0
- package/dist/skill-test/evals-template.d.ts.map +1 -1
- package/dist/skill-test/evals-template.js +27 -10
- package/dist/skill-test/evals-template.js.map +1 -1
- package/dist/skill-test/exit-codes.d.ts +44 -5
- package/dist/skill-test/exit-codes.d.ts.map +1 -1
- package/dist/skill-test/exit-codes.js +63 -9
- package/dist/skill-test/exit-codes.js.map +1 -1
- package/dist/skill-test/experimenter-prompt.d.ts +22 -0
- package/dist/skill-test/experimenter-prompt.d.ts.map +1 -1
- package/dist/skill-test/experimenter-prompt.js +39 -2
- package/dist/skill-test/experimenter-prompt.js.map +1 -1
- package/dist/skill-test/grading-adapter.d.ts +42 -0
- package/dist/skill-test/grading-adapter.d.ts.map +1 -1
- package/dist/skill-test/grading-adapter.js +63 -1
- package/dist/skill-test/grading-adapter.js.map +1 -1
- package/dist/skill-test/grading-schema.d.ts +73 -5
- package/dist/skill-test/grading-schema.d.ts.map +1 -1
- package/dist/skill-test/grading-schema.js +20 -5
- package/dist/skill-test/grading-schema.js.map +1 -1
- package/dist/skill-test/harness-location.d.ts +35 -4
- package/dist/skill-test/harness-location.d.ts.map +1 -1
- package/dist/skill-test/harness-location.js +111 -16
- package/dist/skill-test/harness-location.js.map +1 -1
- package/dist/skill-test/index.d.ts +7 -4
- package/dist/skill-test/index.d.ts.map +1 -1
- package/dist/skill-test/index.js +7 -4
- package/dist/skill-test/index.js.map +1 -1
- package/dist/skill-test/lock.d.ts +23 -0
- package/dist/skill-test/lock.d.ts.map +1 -1
- package/dist/skill-test/lock.js +35 -1
- package/dist/skill-test/lock.js.map +1 -1
- package/dist/skill-test/plugin-env.d.ts +20 -0
- package/dist/skill-test/plugin-env.d.ts.map +1 -0
- package/dist/skill-test/plugin-env.js +24 -0
- package/dist/skill-test/plugin-env.js.map +1 -0
- package/dist/skill-test/plugin-layout.d.ts +41 -0
- package/dist/skill-test/plugin-layout.d.ts.map +1 -0
- package/dist/skill-test/plugin-layout.js +49 -0
- package/dist/skill-test/plugin-layout.js.map +1 -0
- package/dist/skill-test/preflight.d.ts.map +1 -1
- package/dist/skill-test/preflight.js +1 -2
- package/dist/skill-test/preflight.js.map +1 -1
- package/dist/skill-test/run-harness.d.ts +197 -11
- package/dist/skill-test/run-harness.d.ts.map +1 -1
- package/dist/skill-test/run-harness.js +401 -65
- package/dist/skill-test/run-harness.js.map +1 -1
- package/dist/skill-test/staging.d.ts +20 -1
- package/dist/skill-test/staging.d.ts.map +1 -1
- package/dist/skill-test/staging.js +71 -17
- package/dist/skill-test/staging.js.map +1 -1
- package/dist/skill-test/vendor-manifest.d.ts +3 -3
- package/dist/skill-test/vendor-manifest.d.ts.map +1 -1
- package/dist/skill-test/vendor-manifest.js +13 -3
- package/dist/skill-test/vendor-manifest.js.map +1 -1
- package/dist/validators/packaging-validator.d.ts.map +1 -1
- package/dist/validators/packaging-validator.js +134 -1
- package/dist/validators/packaging-validator.js.map +1 -1
- package/dist/validators/skill-validator.d.ts.map +1 -1
- package/dist/validators/skill-validator.js +18 -14
- package/dist/validators/skill-validator.js.map +1 -1
- package/dist/walk-link-graph.d.ts.map +1 -1
- package/dist/walk-link-graph.js +26 -1
- package/dist/walk-link-graph.js.map +1 -1
- package/package.json +6 -5
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { AuthPreflightError } from '@vibe-agent-toolkit/utils';
|
|
2
|
+
import { BuildHookError } from './build-hook.js';
|
|
3
|
+
import { UnknownEnvTokenError } from './declared-env.js';
|
|
2
4
|
import { PromptInvariantError } from './experimenter-prompt.js';
|
|
3
|
-
import { GradingSkewError } from './grading-adapter.js';
|
|
5
|
+
import { GradingNonceError, GradingSkewError } from './grading-adapter.js';
|
|
4
6
|
import { HarnessLocationError } from './harness-location.js';
|
|
5
7
|
/** Exit codes for `vat skill test` (spec §6d). */
|
|
6
8
|
export const SkillTestExitCode = {
|
|
@@ -8,21 +10,58 @@ export const SkillTestExitCode = {
|
|
|
8
10
|
Internal: 1,
|
|
9
11
|
Preflight: 2,
|
|
10
12
|
Bootstrap: 3,
|
|
13
|
+
/**
|
|
14
|
+
* At least one eval FAILED and the caller opted into eval-gating via
|
|
15
|
+
* `--fail-on-eval-failure`. Distinct from the harness-broke codes (1/2):
|
|
16
|
+
* the harness ran to completion and produced a valid grading.json — the
|
|
17
|
+
* skill's expectations simply did not all pass. Returned DIRECTLY by the
|
|
18
|
+
* harness verdict (see verdictExitCode in run-harness.ts), not via
|
|
19
|
+
* mapErrorToExitCode, because it is an outcome, not a thrown error.
|
|
20
|
+
*/
|
|
21
|
+
EvalFailure: 4,
|
|
11
22
|
};
|
|
12
23
|
/**
|
|
13
24
|
* A required input is absent in a way vat can scaffold (missing evals.json).
|
|
14
|
-
* Exit 3, NOT a failure. `expectedPath` is the
|
|
15
|
-
*
|
|
25
|
+
* Exit 3, NOT a failure. `expectedPath` is the persistent location of the
|
|
26
|
+
* annotated starter template.
|
|
27
|
+
*
|
|
28
|
+
* In a real run the harness has already written that template, and the message
|
|
29
|
+
* says so. Under `--dry-run` nothing is written — a dry run must never touch the
|
|
30
|
+
* filesystem — so the message instead describes what a real run *would* scaffold
|
|
31
|
+
* and where, while surfacing the same exit-3 "bootstrap needed" signal.
|
|
16
32
|
*/
|
|
17
33
|
export class BootstrapNeededError extends Error {
|
|
18
34
|
expectedPath;
|
|
19
35
|
exitCode = 3;
|
|
20
|
-
constructor(expectedPath) {
|
|
21
|
-
super(
|
|
36
|
+
constructor(expectedPath, opts) {
|
|
37
|
+
super(opts?.dryRun === true
|
|
38
|
+
? `[dry-run] No evals.json found. A real run would scaffold an annotated template at ${expectedPath} — fill it in and re-run. (dry-run: nothing was written.)`
|
|
39
|
+
: `Wrote an evals.json template at ${expectedPath} — fill it in and re-run.`);
|
|
22
40
|
this.expectedPath = expectedPath;
|
|
23
41
|
this.name = 'BootstrapNeededError';
|
|
24
42
|
}
|
|
25
43
|
}
|
|
44
|
+
/** Thrown when building a declared skill (pool packageSkill or plugin build) fails. Exit 2 (preflight class). */
|
|
45
|
+
export class SkillBuildError extends Error {
|
|
46
|
+
exitCode = 2;
|
|
47
|
+
constructor(message) {
|
|
48
|
+
super(message);
|
|
49
|
+
this.name = 'SkillBuildError';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The §12 security acknowledgment is required but absent, thrown BEFORE any
|
|
54
|
+
* build/pre-stage command (which executes untrusted repo code) runs for a
|
|
55
|
+
* buildable subject. Exit 2 (preflight class). Mirrors the harness Step-6 ack
|
|
56
|
+
* message wording so the two enforcement points read identically.
|
|
57
|
+
*/
|
|
58
|
+
export class SecurityAckError extends Error {
|
|
59
|
+
exitCode = 2;
|
|
60
|
+
constructor() {
|
|
61
|
+
super('Security acknowledgment required. Pass --i-understand-this-runs-skill-code to proceed.');
|
|
62
|
+
this.name = 'SecurityAckError';
|
|
63
|
+
}
|
|
64
|
+
}
|
|
26
65
|
/** Internal harness failure (incl. experimenter exiting without valid grading.json). Exit 1. */
|
|
27
66
|
export class InternalHarnessError extends Error {
|
|
28
67
|
exitCode = 1;
|
|
@@ -35,19 +74,34 @@ export class InternalHarnessError extends Error {
|
|
|
35
74
|
* Map any thrown error to the process exit code. Errors that carry their own
|
|
36
75
|
* `exitCode` (Bootstrap/Auth/HarnessLocation/Internal) are authoritative;
|
|
37
76
|
* a PromptInvariantError is a user-correctable preflight problem (a supplied
|
|
38
|
-
* prompt override is missing a required safety instruction) → 2;
|
|
39
|
-
* is a
|
|
77
|
+
* prompt override is missing a required safety instruction) → 2; a BuildHookError
|
|
78
|
+
* is a pre-stage build failure → 2; a SkillBuildError is a declared-skill build
|
|
79
|
+
* failure → 2; a SecurityAckError is a missing security ack before a build → 2;
|
|
80
|
+
* an UnknownEnvTokenError is a bad ${token} in a
|
|
81
|
+
* declared env value → 2; GradingSkewError (parse failure) and GradingNonceError
|
|
82
|
+
* (forged/mismatched grading nonce) are both → 1; everything unknown → 1.
|
|
83
|
+
*
|
|
84
|
+
* Note: SkillTestExitCode.EvalFailure (4) is NOT produced here — it is an
|
|
85
|
+
* outcome of a completed run (an eval failed under `--fail-on-eval-failure`),
|
|
86
|
+
* not a thrown error, so the harness returns it directly (see verdictExitCode).
|
|
40
87
|
*/
|
|
41
88
|
export function mapErrorToExitCode(err) {
|
|
42
89
|
if (err instanceof BootstrapNeededError)
|
|
43
90
|
return SkillTestExitCode.Bootstrap;
|
|
44
91
|
if (err instanceof AuthPreflightError ||
|
|
92
|
+
err instanceof BuildHookError ||
|
|
45
93
|
err instanceof HarnessLocationError ||
|
|
46
|
-
err instanceof PromptInvariantError
|
|
94
|
+
err instanceof PromptInvariantError ||
|
|
95
|
+
err instanceof SecurityAckError ||
|
|
96
|
+
err instanceof SkillBuildError ||
|
|
97
|
+
err instanceof UnknownEnvTokenError) {
|
|
47
98
|
return SkillTestExitCode.Preflight;
|
|
48
99
|
}
|
|
49
|
-
if (err instanceof
|
|
100
|
+
if (err instanceof GradingNonceError ||
|
|
101
|
+
err instanceof GradingSkewError ||
|
|
102
|
+
err instanceof InternalHarnessError) {
|
|
50
103
|
return SkillTestExitCode.Internal;
|
|
104
|
+
}
|
|
51
105
|
return SkillTestExitCode.Internal;
|
|
52
106
|
}
|
|
53
107
|
//# sourceMappingURL=exit-codes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../../src/skill-test/exit-codes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../../src/skill-test/exit-codes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D,kDAAkD;AAClD,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,EAAE,EAAE,CAAC;IACL,QAAQ,EAAE,CAAC;IACX,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC;IACZ;;;;;;;OAOG;IACH,WAAW,EAAE,CAAC;CACN,CAAC;AAIX;;;;;;;;;GASG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAEjB;IADnB,QAAQ,GAAG,CAAU,CAAC;IAC/B,YAA4B,YAAoB,EAAE,IAA2B;QAC3E,KAAK,CACH,IAAI,EAAE,MAAM,KAAK,IAAI;YACnB,CAAC,CAAC,qFAAqF,YAAY,2DAA2D;YAC9J,CAAC,CAAC,mCAAmC,YAAY,2BAA2B,CAC/E,CAAC;QALwB,iBAAY,GAAZ,YAAY,CAAQ;QAM9C,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,iHAAiH;AACjH,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,QAAQ,GAAG,CAAU,CAAC;IAC/B,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAChC,QAAQ,GAAG,CAAU,CAAC;IAC/B;QACE,KAAK,CAAC,wFAAwF,CAAC,CAAC;QAChG,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED,gGAAgG;AAChG,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IACpC,QAAQ,GAAG,CAAU,CAAC;IAC/B,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAY;IAC7C,IAAI,GAAG,YAAY,oBAAoB;QAAE,OAAO,iBAAiB,CAAC,SAAS,CAAC;IAC5E,IACE,GAAG,YAAY,kBAAkB;QACjC,GAAG,YAAY,cAAc;QAC7B,GAAG,YAAY,oBAAoB;QACnC,GAAG,YAAY,oBAAoB;QACnC,GAAG,YAAY,gBAAgB;QAC/B,GAAG,YAAY,eAAe;QAC9B,GAAG,YAAY,oBAAoB,EACnC,CAAC;QACD,OAAO,iBAAiB,CAAC,SAAS,CAAC;IACrC,CAAC;IACD,IACE,GAAG,YAAY,iBAAiB;QAChC,GAAG,YAAY,gBAAgB;QAC/B,GAAG,YAAY,oBAAoB,EACnC,CAAC;QACD,OAAO,iBAAiB,CAAC,QAAQ,CAAC;IACpC,CAAC;IACD,OAAO,iBAAiB,CAAC,QAAQ,CAAC;AACpC,CAAC"}
|
|
@@ -6,6 +6,7 @@ export interface BuildPromptOptions {
|
|
|
6
6
|
evalsPath: string;
|
|
7
7
|
gradingOut: string;
|
|
8
8
|
frictionOut: string;
|
|
9
|
+
workspacesRoot: string;
|
|
9
10
|
baseline: boolean;
|
|
10
11
|
}
|
|
11
12
|
/**
|
|
@@ -16,5 +17,26 @@ export interface BuildPromptOptions {
|
|
|
16
17
|
*/
|
|
17
18
|
export declare const DEFAULT_EXPERIMENTER_PROMPT: string;
|
|
18
19
|
export declare function buildExperimenterPrompt(opts: BuildPromptOptions): string;
|
|
20
|
+
/**
|
|
21
|
+
* Sentinel the persisted (audit) copy of the prompt shows in place of the real
|
|
22
|
+
* nonce, so the on-disk artifact never leaks the secret to skill code.
|
|
23
|
+
*/
|
|
24
|
+
export declare const REDACTED_NONCE_PLACEHOLDER = "<run-nonce redacted>";
|
|
25
|
+
/**
|
|
26
|
+
* Append the per-run integrity-nonce directive to the effective prompt. The
|
|
27
|
+
* experimenter must copy `nonce` verbatim into grading.json's top-level
|
|
28
|
+
* `runNonce` field; the harness then rejects any grading.json whose nonce is
|
|
29
|
+
* absent or wrong (see run-harness.ts). This is defense-in-depth against
|
|
30
|
+
* untrusted skill code forging a passing grading.json in the shared sandbox —
|
|
31
|
+
* without the secret nonce (delivered only via stdin, never written to disk) a
|
|
32
|
+
* forged grading cannot be authenticated.
|
|
33
|
+
*
|
|
34
|
+
* Appended AFTER assertPromptInvariants and AFTER any user `experimenterPrompt`
|
|
35
|
+
* override, so the nonce requirement is ALWAYS enforced and a committed config
|
|
36
|
+
* cannot opt out of it.
|
|
37
|
+
*/
|
|
38
|
+
export declare function appendIntegrityNonceDirective(prompt: string, nonce: string): string;
|
|
39
|
+
/** Redact the per-run nonce from a prompt for the on-disk audit copy. */
|
|
40
|
+
export declare function redactNonce(prompt: string, nonce: string): string;
|
|
19
41
|
export declare function assertPromptInvariants(prompt: string): void;
|
|
20
42
|
//# sourceMappingURL=experimenter-prompt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"experimenter-prompt.d.ts","sourceRoot":"","sources":["../../src/skill-test/experimenter-prompt.ts"],"names":[],"mappings":"AAAA,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,
|
|
1
|
+
{"version":3,"file":"experimenter-prompt.d.ts","sourceRoot":"","sources":["../../src/skill-test/experimenter-prompt.ts"],"names":[],"mappings":"AAAA,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,QA2B5B,CAAC;AAKb,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAQxE;AAED;;;GAGG;AACH,eAAO,MAAM,0BAA0B,yBAAyB,CAAC;AAEjE;;;;;;;;;;;;GAYG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQnF;AAED,yEAAyE;AACzE,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjE;AAmBD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAI3D"}
|
|
@@ -15,11 +15,16 @@ export const DEFAULT_EXPERIMENTER_PROMPT = [
|
|
|
15
15
|
'',
|
|
16
16
|
'For each eval in {{EVALS_PATH}}:',
|
|
17
17
|
' 1. Dispatch ONE executor subagent. Tell it ONLY the task prompt and the staged subject path {{SUBJECT_PATH}}.',
|
|
18
|
-
'
|
|
18
|
+
' When the eval declares input `files`, ALSO tell the executor its working directory is {{WORKSPACES_ROOT}}/<id>',
|
|
19
|
+
' (substitute the eval\'s own id) — the project it should operate on. Never tell the executor it is being tested.',
|
|
19
20
|
' 2. Grade the executor output against the eval\'s `expectations` using skill-creator\'s grader.md rubric.',
|
|
21
|
+
' If the eval includes an `expected_output`, treat it as the author\'s prose description of a',
|
|
22
|
+
' correct result and use it as CONTEXT when judging — but the pass/fail verdict is still decided',
|
|
23
|
+
' per `expectations` entry; `expected_output` informs your judgment, it is not itself a checklist item.',
|
|
20
24
|
' 3. Append each graded expectation to the SINGLE top-level `expectations` array in {{GRADING_OUT}} IMMEDIATELY',
|
|
21
25
|
' (incremental flush — a mid-run kill must leave partial results).',
|
|
22
|
-
' 4. Record any packaging-fidelity friction to {{FRICTION_OUT}} using the vat friction schema.',
|
|
26
|
+
' 4. Record any packaging-fidelity friction to {{FRICTION_OUT}} using the vat friction.json schema.',
|
|
27
|
+
' If a file referenced by the skill is absent from the staged tree, record a `missing-bundled-file` friction entry.',
|
|
23
28
|
'',
|
|
24
29
|
'{{GRADING_OUT}} MUST be ONE flat JSON object in skill-creator\'s grading.json shape (references/schemas.md):',
|
|
25
30
|
'a top-level `expectations` array — one entry {"text","passed","evidence"} per expectation across ALL evals —',
|
|
@@ -38,10 +43,42 @@ export function buildExperimenterPrompt(opts) {
|
|
|
38
43
|
return DEFAULT_EXPERIMENTER_PROMPT
|
|
39
44
|
.replace('{{EVALS_PATH}}', opts.evalsPath)
|
|
40
45
|
.replace('{{SUBJECT_PATH}}', opts.subjectPath)
|
|
46
|
+
.replaceAll('{{WORKSPACES_ROOT}}', opts.workspacesRoot)
|
|
41
47
|
.replaceAll('{{GRADING_OUT}}', opts.gradingOut)
|
|
42
48
|
.replace('{{FRICTION_OUT}}', opts.frictionOut)
|
|
43
49
|
.replace('{{BASELINE_BLOCK}}', opts.baseline ? BASELINE_BLOCK : '');
|
|
44
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Sentinel the persisted (audit) copy of the prompt shows in place of the real
|
|
53
|
+
* nonce, so the on-disk artifact never leaks the secret to skill code.
|
|
54
|
+
*/
|
|
55
|
+
export const REDACTED_NONCE_PLACEHOLDER = '<run-nonce redacted>';
|
|
56
|
+
/**
|
|
57
|
+
* Append the per-run integrity-nonce directive to the effective prompt. The
|
|
58
|
+
* experimenter must copy `nonce` verbatim into grading.json's top-level
|
|
59
|
+
* `runNonce` field; the harness then rejects any grading.json whose nonce is
|
|
60
|
+
* absent or wrong (see run-harness.ts). This is defense-in-depth against
|
|
61
|
+
* untrusted skill code forging a passing grading.json in the shared sandbox —
|
|
62
|
+
* without the secret nonce (delivered only via stdin, never written to disk) a
|
|
63
|
+
* forged grading cannot be authenticated.
|
|
64
|
+
*
|
|
65
|
+
* Appended AFTER assertPromptInvariants and AFTER any user `experimenterPrompt`
|
|
66
|
+
* override, so the nonce requirement is ALWAYS enforced and a committed config
|
|
67
|
+
* cannot opt out of it.
|
|
68
|
+
*/
|
|
69
|
+
export function appendIntegrityNonceDirective(prompt, nonce) {
|
|
70
|
+
return [
|
|
71
|
+
prompt,
|
|
72
|
+
'',
|
|
73
|
+
'INTEGRITY (required, do this LAST): the grading.json you write MUST include a',
|
|
74
|
+
`top-level string field "runNonce" whose value is EXACTLY: ${nonce}`,
|
|
75
|
+
'Copy it verbatim. vat rejects a grading.json whose runNonce is missing or wrong.',
|
|
76
|
+
].join('\n');
|
|
77
|
+
}
|
|
78
|
+
/** Redact the per-run nonce from a prompt for the on-disk audit copy. */
|
|
79
|
+
export function redactNonce(prompt, nonce) {
|
|
80
|
+
return prompt.replaceAll(nonce, REDACTED_NONCE_PLACEHOLDER);
|
|
81
|
+
}
|
|
45
82
|
const REQUIRED_PATTERNS = [
|
|
46
83
|
{ test: /\bSTOP\b/, label: 'must instruct the experimenter to STOP' },
|
|
47
84
|
{ test: /grading\.json|\{\{GRADING_OUT\}\}/i, label: 'must write grading.json' },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"experimenter-prompt.js","sourceRoot":"","sources":["../../src/skill-test/experimenter-prompt.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,YAAY,OAAe;QACzB,KAAK,CAAC,2CAA2C,OAAO,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"experimenter-prompt.js","sourceRoot":"","sources":["../../src/skill-test/experimenter-prompt.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,48 @@ export interface NormalizedGrading {
|
|
|
17
17
|
passed: boolean;
|
|
18
18
|
evidence?: string;
|
|
19
19
|
}[];
|
|
20
|
+
/** Per-run integrity nonce the experimenter copied from its prompt (if present). */
|
|
21
|
+
runNonce?: string;
|
|
20
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Thrown when grading.json's per-run integrity nonce is absent or does not match
|
|
25
|
+
* the nonce the harness stamped into the experimenter prompt for THIS run. A
|
|
26
|
+
* missing/wrong nonce means the grading was not produced by the experimenter we
|
|
27
|
+
* prompted — most likely a grading.json forged or left behind by untrusted skill
|
|
28
|
+
* code in the shared sandbox — so the verdict cannot be trusted.
|
|
29
|
+
*/
|
|
30
|
+
export declare class GradingNonceError extends Error {
|
|
31
|
+
constructor(message: string);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Assert grading.json carries the exact per-run nonce the harness expected.
|
|
35
|
+
* Called before the verdict is trusted. Throws {@link GradingNonceError} on a
|
|
36
|
+
* missing or mismatched nonce.
|
|
37
|
+
*/
|
|
38
|
+
export declare function assertGradingNonce(actual: string | undefined, expected: string): void;
|
|
21
39
|
export declare function parseGradingJson(raw: unknown): NormalizedGrading;
|
|
40
|
+
/** The authoritative eval verdict, recomputed from per-expectation `passed` flags. */
|
|
41
|
+
export interface GradingVerdict {
|
|
42
|
+
passed: number;
|
|
43
|
+
total: number;
|
|
44
|
+
allPassed: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Reconcile the grader's self-reported `summary` against the authoritative
|
|
48
|
+
* per-expectation `passed` flags and return the recomputed verdict.
|
|
49
|
+
*
|
|
50
|
+
* The grader emits BOTH an aggregate `summary.{passed,total}` AND one
|
|
51
|
+
* `expectations[]` entry per graded expectation (each with its own `passed`).
|
|
52
|
+
* The schema (docs/skill-test-grading-schema.md) defines `summary` as the exact
|
|
53
|
+
* aggregate of `expectations`, so the two MUST agree. We never trust the
|
|
54
|
+
* self-reported summary alone — a grader that emits `summary {5,5}` alongside a
|
|
55
|
+
* failing expectation would otherwise be a false green.
|
|
56
|
+
*
|
|
57
|
+
* Throws {@link GradingSkewError} when:
|
|
58
|
+
* - there are zero expectations (the grader graded NOTHING — an error, never a
|
|
59
|
+
* pass); or
|
|
60
|
+
* - the summary disagrees with the recomputed counts (a grader bug, surfaced
|
|
61
|
+
* loudly rather than silently flowing a wrong verdict downstream).
|
|
62
|
+
*/
|
|
63
|
+
export declare function reconcileGrading(report: NormalizedGrading): GradingVerdict;
|
|
22
64
|
//# sourceMappingURL=grading-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grading-adapter.d.ts","sourceRoot":"","sources":["../../src/skill-test/grading-adapter.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAQ5B;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"grading-adapter.d.ts","sourceRoot":"","sources":["../../src/skill-test/grading-adapter.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAQ5B;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACrE,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAS5B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAOrF;AAaD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,iBAAiB,CAwBhE;AAED,sFAAsF;AACtF,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,GAAG,cAAc,CAqB1E"}
|
|
@@ -13,6 +13,35 @@ export class GradingSkewError extends Error {
|
|
|
13
13
|
this.name = 'GradingSkewError';
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Thrown when grading.json's per-run integrity nonce is absent or does not match
|
|
18
|
+
* the nonce the harness stamped into the experimenter prompt for THIS run. A
|
|
19
|
+
* missing/wrong nonce means the grading was not produced by the experimenter we
|
|
20
|
+
* prompted — most likely a grading.json forged or left behind by untrusted skill
|
|
21
|
+
* code in the shared sandbox — so the verdict cannot be trusted.
|
|
22
|
+
*/
|
|
23
|
+
export class GradingNonceError extends Error {
|
|
24
|
+
constructor(message) {
|
|
25
|
+
super(`grading.json integrity check failed: ${message}. The harness stamps a secret ` +
|
|
26
|
+
'per-run nonce into the experimenter prompt (never written to disk) and requires ' +
|
|
27
|
+
'grading.json to echo it; a missing or wrong nonce means the grading was not ' +
|
|
28
|
+
'produced by the prompted experimenter and is rejected.');
|
|
29
|
+
this.name = 'GradingNonceError';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Assert grading.json carries the exact per-run nonce the harness expected.
|
|
34
|
+
* Called before the verdict is trusted. Throws {@link GradingNonceError} on a
|
|
35
|
+
* missing or mismatched nonce.
|
|
36
|
+
*/
|
|
37
|
+
export function assertGradingNonce(actual, expected) {
|
|
38
|
+
if (actual === undefined) {
|
|
39
|
+
throw new GradingNonceError('grading.json has no top-level `runNonce`');
|
|
40
|
+
}
|
|
41
|
+
if (actual !== expected) {
|
|
42
|
+
throw new GradingNonceError('grading.json `runNonce` does not match this run');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
16
45
|
/**
|
|
17
46
|
* Detect the common per-eval nested mistake: `{ evals: [ { expectations, ... } ] }`
|
|
18
47
|
* with no top-level `expectations`. The grader (an LLM) reaches for this when the
|
|
@@ -36,7 +65,7 @@ export function parseGradingJson(raw) {
|
|
|
36
65
|
const path = firstIssue?.path.join('.') ?? '(root)';
|
|
37
66
|
throw new GradingSkewError(`missing/invalid field at "${path}" (${firstIssue?.message ?? 'unknown'})`);
|
|
38
67
|
}
|
|
39
|
-
const { summary, expectations } = result.data;
|
|
68
|
+
const { summary, expectations, runNonce } = result.data;
|
|
40
69
|
return {
|
|
41
70
|
summary: { passed: summary.passed, total: summary.total },
|
|
42
71
|
expectations: expectations.map(e => ({
|
|
@@ -44,6 +73,39 @@ export function parseGradingJson(raw) {
|
|
|
44
73
|
passed: e.passed,
|
|
45
74
|
...(e.evidence === undefined ? {} : { evidence: e.evidence }),
|
|
46
75
|
})),
|
|
76
|
+
...(runNonce === undefined ? {} : { runNonce }),
|
|
47
77
|
};
|
|
48
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Reconcile the grader's self-reported `summary` against the authoritative
|
|
81
|
+
* per-expectation `passed` flags and return the recomputed verdict.
|
|
82
|
+
*
|
|
83
|
+
* The grader emits BOTH an aggregate `summary.{passed,total}` AND one
|
|
84
|
+
* `expectations[]` entry per graded expectation (each with its own `passed`).
|
|
85
|
+
* The schema (docs/skill-test-grading-schema.md) defines `summary` as the exact
|
|
86
|
+
* aggregate of `expectations`, so the two MUST agree. We never trust the
|
|
87
|
+
* self-reported summary alone — a grader that emits `summary {5,5}` alongside a
|
|
88
|
+
* failing expectation would otherwise be a false green.
|
|
89
|
+
*
|
|
90
|
+
* Throws {@link GradingSkewError} when:
|
|
91
|
+
* - there are zero expectations (the grader graded NOTHING — an error, never a
|
|
92
|
+
* pass); or
|
|
93
|
+
* - the summary disagrees with the recomputed counts (a grader bug, surfaced
|
|
94
|
+
* loudly rather than silently flowing a wrong verdict downstream).
|
|
95
|
+
*/
|
|
96
|
+
export function reconcileGrading(report) {
|
|
97
|
+
const computedPassed = report.expectations.filter(e => e.passed).length;
|
|
98
|
+
const computedTotal = report.expectations.length;
|
|
99
|
+
if (computedTotal === 0) {
|
|
100
|
+
throw new GradingSkewError('the grader recorded zero expectations — nothing was graded, so this can never be a pass. ' +
|
|
101
|
+
'A valid grading.json lists every graded expectation in top-level `expectations`');
|
|
102
|
+
}
|
|
103
|
+
const { passed, total } = report.summary;
|
|
104
|
+
if (passed !== computedPassed || total !== computedTotal) {
|
|
105
|
+
throw new GradingSkewError(`the grader's summary disagrees with its expectations: summary={passed:${passed},total:${total}} ` +
|
|
106
|
+
`but expectations recompute to {passed:${computedPassed},total:${computedTotal}}. ` +
|
|
107
|
+
'`summary` must be the exact aggregate of `expectations` (one entry per graded expectation)');
|
|
108
|
+
}
|
|
109
|
+
return { passed: computedPassed, total: computedTotal, allPassed: computedPassed === computedTotal };
|
|
110
|
+
}
|
|
49
111
|
//# sourceMappingURL=grading-adapter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grading-adapter.js","sourceRoot":"","sources":["../../src/skill-test/grading-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;GAKG;AACH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAe;QACzB,KAAK,CACH,4BAA4B,OAAO,gDAAgD;YACjF,0EAA0E;YAC1E,yFAAyF,CAC5F,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"grading-adapter.js","sourceRoot":"","sources":["../../src/skill-test/grading-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;GAKG;AACH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAe;QACzB,KAAK,CACH,4BAA4B,OAAO,gDAAgD;YACjF,0EAA0E;YAC1E,yFAAyF,CAC5F,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AASD;;;;;;GAMG;AACH,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAe;QACzB,KAAK,CACH,wCAAwC,OAAO,gCAAgC;YAC7E,kFAAkF;YAClF,8EAA8E;YAC9E,wDAAwD,CAC3D,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAA0B,EAAE,QAAgB;IAC7E,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,iBAAiB,CAAC,0CAA0C,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,MAAM,IAAI,iBAAiB,CAAC,iDAAiD,CAAC,CAAC;IACjF,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,GAAY;IACtC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC1D,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,IAAI,GAAG,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAY;IAC3C,MAAM,MAAM,GAAG,mBAAmB,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAClD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,gBAAgB,CACxB,oFAAoF;gBAClF,kFAAkF;gBAClF,qCAAqC,CACxC,CAAC;QACJ,CAAC;QACD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC;QACpD,MAAM,IAAI,gBAAgB,CAAC,6BAA6B,IAAI,MAAM,UAAU,EAAE,OAAO,IAAI,SAAS,GAAG,CAAC,CAAC;IACzG,CAAC;IACD,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;IACxD,OAAO;QACL,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;QACzD,YAAY,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACnC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,GAAG,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;SAC9D,CAAC,CAAC;QACH,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC;KAChD,CAAC;AACJ,CAAC;AASD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAyB;IACxD,MAAM,cAAc,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;IACxE,MAAM,aAAa,GAAG,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC;IAEjD,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,gBAAgB,CACxB,2FAA2F;YACzF,iFAAiF,CACpF,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC;IACzC,IAAI,MAAM,KAAK,cAAc,IAAI,KAAK,KAAK,aAAa,EAAE,CAAC;QACzD,MAAM,IAAI,gBAAgB,CACxB,yEAAyE,MAAM,UAAU,KAAK,IAAI;YAChG,yCAAyC,cAAc,UAAU,aAAa,KAAK;YACnF,4FAA4F,CAC/F,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,cAAc,KAAK,aAAa,EAAE,CAAC;AACvG,CAAC"}
|
|
@@ -41,8 +41,12 @@ export declare const GradedExpectationSchema: z.ZodObject<{
|
|
|
41
41
|
evidence: z.ZodOptional<z.ZodString>;
|
|
42
42
|
}, z.ZodTypeAny, "passthrough">>;
|
|
43
43
|
export type GradedExpectation = z.infer<typeof GradedExpectationSchema>;
|
|
44
|
-
/**
|
|
45
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Aggregate pass/fail counts. `failed`/`pass_rate` are documented but optional.
|
|
46
|
+
* Counts are non-negative integers (a float or negative count is a grader bug),
|
|
47
|
+
* and `passed` can never exceed `total`.
|
|
48
|
+
*/
|
|
49
|
+
export declare const GradingSummarySchema: z.ZodEffects<z.ZodObject<{
|
|
46
50
|
passed: z.ZodNumber;
|
|
47
51
|
total: z.ZodNumber;
|
|
48
52
|
failed: z.ZodOptional<z.ZodNumber>;
|
|
@@ -57,6 +61,16 @@ export declare const GradingSummarySchema: z.ZodObject<{
|
|
|
57
61
|
total: z.ZodNumber;
|
|
58
62
|
failed: z.ZodOptional<z.ZodNumber>;
|
|
59
63
|
pass_rate: z.ZodOptional<z.ZodNumber>;
|
|
64
|
+
}, z.ZodTypeAny, "passthrough">>, z.objectOutputType<{
|
|
65
|
+
passed: z.ZodNumber;
|
|
66
|
+
total: z.ZodNumber;
|
|
67
|
+
failed: z.ZodOptional<z.ZodNumber>;
|
|
68
|
+
pass_rate: z.ZodOptional<z.ZodNumber>;
|
|
69
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
70
|
+
passed: z.ZodNumber;
|
|
71
|
+
total: z.ZodNumber;
|
|
72
|
+
failed: z.ZodOptional<z.ZodNumber>;
|
|
73
|
+
pass_rate: z.ZodOptional<z.ZodNumber>;
|
|
60
74
|
}, z.ZodTypeAny, "passthrough">>;
|
|
61
75
|
export type GradingSummary = z.infer<typeof GradingSummarySchema>;
|
|
62
76
|
/**
|
|
@@ -78,7 +92,7 @@ export declare const GradingReportSchema: z.ZodObject<{
|
|
|
78
92
|
passed: z.ZodBoolean;
|
|
79
93
|
evidence: z.ZodOptional<z.ZodString>;
|
|
80
94
|
}, z.ZodTypeAny, "passthrough">>, "many">;
|
|
81
|
-
summary: z.ZodObject<{
|
|
95
|
+
summary: z.ZodEffects<z.ZodObject<{
|
|
82
96
|
passed: z.ZodNumber;
|
|
83
97
|
total: z.ZodNumber;
|
|
84
98
|
failed: z.ZodOptional<z.ZodNumber>;
|
|
@@ -93,7 +107,25 @@ export declare const GradingReportSchema: z.ZodObject<{
|
|
|
93
107
|
total: z.ZodNumber;
|
|
94
108
|
failed: z.ZodOptional<z.ZodNumber>;
|
|
95
109
|
pass_rate: z.ZodOptional<z.ZodNumber>;
|
|
110
|
+
}, z.ZodTypeAny, "passthrough">>, z.objectOutputType<{
|
|
111
|
+
passed: z.ZodNumber;
|
|
112
|
+
total: z.ZodNumber;
|
|
113
|
+
failed: z.ZodOptional<z.ZodNumber>;
|
|
114
|
+
pass_rate: z.ZodOptional<z.ZodNumber>;
|
|
115
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
116
|
+
passed: z.ZodNumber;
|
|
117
|
+
total: z.ZodNumber;
|
|
118
|
+
failed: z.ZodOptional<z.ZodNumber>;
|
|
119
|
+
pass_rate: z.ZodOptional<z.ZodNumber>;
|
|
96
120
|
}, z.ZodTypeAny, "passthrough">>;
|
|
121
|
+
/**
|
|
122
|
+
* Per-run integrity nonce the experimenter is told to copy verbatim from its
|
|
123
|
+
* prompt (see experimenter-prompt.ts). Optional in the schema (a grading.json
|
|
124
|
+
* validated by external tooling need not carry it), but the harness REQUIRES
|
|
125
|
+
* it to match the run's secret nonce before trusting the verdict — this is how
|
|
126
|
+
* a forged grading.json written by untrusted skill code is rejected.
|
|
127
|
+
*/
|
|
128
|
+
runNonce: z.ZodOptional<z.ZodString>;
|
|
97
129
|
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
98
130
|
expectations: z.ZodArray<z.ZodObject<{
|
|
99
131
|
text: z.ZodString;
|
|
@@ -108,7 +140,7 @@ export declare const GradingReportSchema: z.ZodObject<{
|
|
|
108
140
|
passed: z.ZodBoolean;
|
|
109
141
|
evidence: z.ZodOptional<z.ZodString>;
|
|
110
142
|
}, z.ZodTypeAny, "passthrough">>, "many">;
|
|
111
|
-
summary: z.ZodObject<{
|
|
143
|
+
summary: z.ZodEffects<z.ZodObject<{
|
|
112
144
|
passed: z.ZodNumber;
|
|
113
145
|
total: z.ZodNumber;
|
|
114
146
|
failed: z.ZodOptional<z.ZodNumber>;
|
|
@@ -123,7 +155,25 @@ export declare const GradingReportSchema: z.ZodObject<{
|
|
|
123
155
|
total: z.ZodNumber;
|
|
124
156
|
failed: z.ZodOptional<z.ZodNumber>;
|
|
125
157
|
pass_rate: z.ZodOptional<z.ZodNumber>;
|
|
158
|
+
}, z.ZodTypeAny, "passthrough">>, z.objectOutputType<{
|
|
159
|
+
passed: z.ZodNumber;
|
|
160
|
+
total: z.ZodNumber;
|
|
161
|
+
failed: z.ZodOptional<z.ZodNumber>;
|
|
162
|
+
pass_rate: z.ZodOptional<z.ZodNumber>;
|
|
163
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
164
|
+
passed: z.ZodNumber;
|
|
165
|
+
total: z.ZodNumber;
|
|
166
|
+
failed: z.ZodOptional<z.ZodNumber>;
|
|
167
|
+
pass_rate: z.ZodOptional<z.ZodNumber>;
|
|
126
168
|
}, z.ZodTypeAny, "passthrough">>;
|
|
169
|
+
/**
|
|
170
|
+
* Per-run integrity nonce the experimenter is told to copy verbatim from its
|
|
171
|
+
* prompt (see experimenter-prompt.ts). Optional in the schema (a grading.json
|
|
172
|
+
* validated by external tooling need not carry it), but the harness REQUIRES
|
|
173
|
+
* it to match the run's secret nonce before trusting the verdict — this is how
|
|
174
|
+
* a forged grading.json written by untrusted skill code is rejected.
|
|
175
|
+
*/
|
|
176
|
+
runNonce: z.ZodOptional<z.ZodString>;
|
|
127
177
|
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
128
178
|
expectations: z.ZodArray<z.ZodObject<{
|
|
129
179
|
text: z.ZodString;
|
|
@@ -138,7 +188,7 @@ export declare const GradingReportSchema: z.ZodObject<{
|
|
|
138
188
|
passed: z.ZodBoolean;
|
|
139
189
|
evidence: z.ZodOptional<z.ZodString>;
|
|
140
190
|
}, z.ZodTypeAny, "passthrough">>, "many">;
|
|
141
|
-
summary: z.ZodObject<{
|
|
191
|
+
summary: z.ZodEffects<z.ZodObject<{
|
|
142
192
|
passed: z.ZodNumber;
|
|
143
193
|
total: z.ZodNumber;
|
|
144
194
|
failed: z.ZodOptional<z.ZodNumber>;
|
|
@@ -153,7 +203,25 @@ export declare const GradingReportSchema: z.ZodObject<{
|
|
|
153
203
|
total: z.ZodNumber;
|
|
154
204
|
failed: z.ZodOptional<z.ZodNumber>;
|
|
155
205
|
pass_rate: z.ZodOptional<z.ZodNumber>;
|
|
206
|
+
}, z.ZodTypeAny, "passthrough">>, z.objectOutputType<{
|
|
207
|
+
passed: z.ZodNumber;
|
|
208
|
+
total: z.ZodNumber;
|
|
209
|
+
failed: z.ZodOptional<z.ZodNumber>;
|
|
210
|
+
pass_rate: z.ZodOptional<z.ZodNumber>;
|
|
211
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
212
|
+
passed: z.ZodNumber;
|
|
213
|
+
total: z.ZodNumber;
|
|
214
|
+
failed: z.ZodOptional<z.ZodNumber>;
|
|
215
|
+
pass_rate: z.ZodOptional<z.ZodNumber>;
|
|
156
216
|
}, z.ZodTypeAny, "passthrough">>;
|
|
217
|
+
/**
|
|
218
|
+
* Per-run integrity nonce the experimenter is told to copy verbatim from its
|
|
219
|
+
* prompt (see experimenter-prompt.ts). Optional in the schema (a grading.json
|
|
220
|
+
* validated by external tooling need not carry it), but the harness REQUIRES
|
|
221
|
+
* it to match the run's secret nonce before trusting the verdict — this is how
|
|
222
|
+
* a forged grading.json written by untrusted skill code is rejected.
|
|
223
|
+
*/
|
|
224
|
+
runNonce: z.ZodOptional<z.ZodString>;
|
|
157
225
|
}, z.ZodTypeAny, "passthrough">>;
|
|
158
226
|
export type GradingReport = z.infer<typeof GradingReportSchema>;
|
|
159
227
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grading-schema.d.ts","sourceRoot":"","sources":["../../src/skill-test/grading-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,sFAAsF;AACtF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;gCAMpB,CAAC;AAEjB,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE
|
|
1
|
+
{"version":3,"file":"grading-schema.d.ts","sourceRoot":"","sources":["../../src/skill-test/grading-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,sFAAsF;AACtF,eAAO,MAAM,uBAAuB;;;;;;;;;;;;gCAMpB,CAAC;AAEjB,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;gCAU7B,CAAC;AAEL,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAI5B;;;;;;OAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IANH;;;;;;OAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IANH;;;;;;OAMG;;gCAGS,CAAC;AAEjB,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB;;;;;CAAyD,CAAC"}
|
|
@@ -35,15 +35,22 @@ export const GradedExpectationSchema = z
|
|
|
35
35
|
evidence: z.string().optional(),
|
|
36
36
|
})
|
|
37
37
|
.passthrough();
|
|
38
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* Aggregate pass/fail counts. `failed`/`pass_rate` are documented but optional.
|
|
40
|
+
* Counts are non-negative integers (a float or negative count is a grader bug),
|
|
41
|
+
* and `passed` can never exceed `total`.
|
|
42
|
+
*/
|
|
39
43
|
export const GradingSummarySchema = z
|
|
40
44
|
.object({
|
|
41
|
-
passed: z.number(),
|
|
42
|
-
total: z.number(),
|
|
43
|
-
failed: z.number().optional(),
|
|
45
|
+
passed: z.number().int().nonnegative(),
|
|
46
|
+
total: z.number().int().nonnegative(),
|
|
47
|
+
failed: z.number().int().nonnegative().optional(),
|
|
44
48
|
pass_rate: z.number().optional(),
|
|
45
49
|
})
|
|
46
|
-
.passthrough()
|
|
50
|
+
.passthrough()
|
|
51
|
+
.refine(s => s.passed <= s.total, {
|
|
52
|
+
message: 'summary.passed must not exceed summary.total',
|
|
53
|
+
});
|
|
47
54
|
/**
|
|
48
55
|
* The full grading.json contract. Required: top-level `expectations[]` and
|
|
49
56
|
* `summary`. Everything else passes through untouched (forward-compatible with
|
|
@@ -53,6 +60,14 @@ export const GradingReportSchema = z
|
|
|
53
60
|
.object({
|
|
54
61
|
expectations: z.array(GradedExpectationSchema),
|
|
55
62
|
summary: GradingSummarySchema,
|
|
63
|
+
/**
|
|
64
|
+
* Per-run integrity nonce the experimenter is told to copy verbatim from its
|
|
65
|
+
* prompt (see experimenter-prompt.ts). Optional in the schema (a grading.json
|
|
66
|
+
* validated by external tooling need not carry it), but the harness REQUIRES
|
|
67
|
+
* it to match the run's secret nonce before trusting the verdict — this is how
|
|
68
|
+
* a forged grading.json written by untrusted skill code is rejected.
|
|
69
|
+
*/
|
|
70
|
+
runNonce: z.string().optional(),
|
|
56
71
|
})
|
|
57
72
|
.passthrough();
|
|
58
73
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grading-schema.js","sourceRoot":"","sources":["../../src/skill-test/grading-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,sFAAsF;AACtF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC;KACrC,MAAM,CAAC;IACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE;IACnB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC;KACD,WAAW,EAAE,CAAC;AAIjB
|
|
1
|
+
{"version":3,"file":"grading-schema.js","sourceRoot":"","sources":["../../src/skill-test/grading-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,sFAAsF;AACtF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC;KACrC,MAAM,CAAC;IACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE;IACnB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC;KACD,WAAW,EAAE,CAAC;AAIjB;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC;KAClC,MAAM,CAAC;IACN,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACtC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACrC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;IACjD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC;KACD,WAAW,EAAE;KACb,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,EAAE;IAChC,OAAO,EAAE,8CAA8C;CACxD,CAAC,CAAC;AAIL;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC;KACjC,MAAM,CAAC;IACN,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,uBAAuB,CAAC;IAC9C,OAAO,EAAE,oBAAoB;IAC7B;;;;;;OAMG;IACH,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC;KACD,WAAW,EAAE,CAAC;AAIjB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,eAAe,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CAAC"}
|
|
@@ -15,13 +15,44 @@ export declare function resolveHarnessRoot(skillNames: string[], tmpRoot?: strin
|
|
|
15
15
|
* Refuse a --workdir whose ancestry contains CLAUDE.md or .claude/ — cwd
|
|
16
16
|
* discovery would re-pollute the run (spec §7). Defense in depth with
|
|
17
17
|
* --setting-sources "".
|
|
18
|
+
*
|
|
19
|
+
* `stopAt` (optional) bounds the ancestry walk: when the walk reaches that
|
|
20
|
+
* directory it stops *before* inspecting it (exclusive boundary), mirroring
|
|
21
|
+
* `assertSafeHarnessRoot`'s `trustedRoot`. Default (undefined) walks to the
|
|
22
|
+
* filesystem root, preserving the strictest production behavior. Tests use it
|
|
23
|
+
* to scope the walk to a sandbox — necessary on Windows, where the OS tmp dir
|
|
24
|
+
* lives inside the user's home and would otherwise surface an ambient
|
|
25
|
+
* ~/.claude during the walk.
|
|
18
26
|
*/
|
|
19
|
-
export declare function assertSafeWorkdir(dir: string): void;
|
|
27
|
+
export declare function assertSafeWorkdir(dir: string, stopAt?: string): void;
|
|
20
28
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
29
|
+
* Prepare the harness root directory so that `assertSafeHarnessRoot` will
|
|
30
|
+
* pass on the next call. If the path does not exist, this is a no-op (the
|
|
31
|
+
* caller creates it at 0700 via mkdirSyncReal). If it exists:
|
|
32
|
+
*
|
|
33
|
+
* - Symlink → throw HarnessLocationError (security gate; never relax).
|
|
34
|
+
* - Real directory whose mode != 0700 → chmod to 0700. Removing group/other
|
|
35
|
+
* access is strictly safer, never a relaxation.
|
|
36
|
+
*
|
|
37
|
+
* Mode checks/changes are only performed on non-win32 (matching
|
|
38
|
+
* assertSafeHarnessRoot's platform guard).
|
|
39
|
+
*/
|
|
40
|
+
export declare function prepareHarnessRoot(dir: string): void;
|
|
41
|
+
/**
|
|
42
|
+
* FS-bound hardening for the shared-tmp harness root (spec §7). Validates EVERY
|
|
43
|
+
* path component from the leaf up to (but excluding) `trustedRoot`: no component
|
|
44
|
+
* may be a symlink, and on POSIX each must be owned by the current uid. This
|
|
45
|
+
* closes the shared-/tmp TOCTOU where the recursively-created intermediate parent
|
|
46
|
+
* (`<tmp>/vat-skill-test`) — not just the leaf — could be pre-created as a symlink
|
|
47
|
+
* or under another user's ownership. The leaf must additionally be 0700.
|
|
48
|
+
*
|
|
49
|
+
* `trustedRoot` (default: the OS tmp dir) is the boundary: it is system-owned
|
|
50
|
+
* (sticky-bit /tmp) so ownership/mode checks are not applied to it. When the leaf
|
|
51
|
+
* is not a descendant of `trustedRoot` (an explicit --out elsewhere), validation
|
|
52
|
+
* degrades to the leaf alone.
|
|
53
|
+
*
|
|
23
54
|
* Integration-tested (requires real lstat/stat). On Windows, uid checks are
|
|
24
55
|
* skipped (process.getuid is undefined) but the symlink refusal still applies.
|
|
25
56
|
*/
|
|
26
|
-
export declare function assertSafeHarnessRoot(dir: string, currentUid: number): void;
|
|
57
|
+
export declare function assertSafeHarnessRoot(dir: string, currentUid: number, trustedRoot?: string): void;
|
|
27
58
|
//# sourceMappingURL=harness-location.d.ts.map
|