@cat-factory/sandbox 0.11.162 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/baselines.d.ts +40 -11
- package/dist/baselines.d.ts.map +1 -1
- package/dist/baselines.js +94 -22
- package/dist/baselines.js.map +1 -1
- package/dist/expectations.d.ts +45 -0
- package/dist/expectations.d.ts.map +1 -0
- package/dist/expectations.js +114 -0
- package/dist/expectations.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/rubrics.d.ts +16 -46
- package/dist/rubrics.d.ts.map +1 -1
- package/dist/rubrics.js +213 -88
- package/dist/rubrics.js.map +1 -1
- package/package.json +5 -5
package/dist/baselines.d.ts
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
import type { AgentKindRegistry } from '@cat-factory/agents';
|
|
2
|
-
import type { SandboxFixtureKind } from '@cat-factory/contracts';
|
|
2
|
+
import type { SandboxAgentBucket, SandboxFixtureKind, SandboxRunMode, SandboxUnsupportedReason } from '@cat-factory/contracts';
|
|
3
3
|
import type { SandboxPromptVersion } from '@cat-factory/kernel';
|
|
4
4
|
import type { SandboxTaskType } from './rubrics.js';
|
|
5
|
-
export type SandboxAgentBucket
|
|
5
|
+
export type { SandboxAgentBucket, SandboxRunMode, SandboxUnsupportedReason };
|
|
6
6
|
export interface SandboxAgentKindMeta {
|
|
7
7
|
/** The agent kind (matches `AgentKind` strings used across the product). */
|
|
8
8
|
agentKind: string;
|
|
9
9
|
/** A short human label for the Sandbox prompt browser. */
|
|
10
10
|
label: string;
|
|
11
|
-
/**
|
|
11
|
+
/** How PRODUCTION dispatches this kind. */
|
|
12
12
|
bucket: SandboxAgentBucket;
|
|
13
|
+
/** How the SANDBOX runs a cell for it; `unsupported` ⇒ {@link unsupportedReason} says why. */
|
|
14
|
+
sandboxRun: SandboxRunMode;
|
|
15
|
+
/**
|
|
16
|
+
* Why the Sandbox cannot run this kind, as a bounded CODE. Non-null exactly when
|
|
17
|
+
* `sandboxRun === 'unsupported'` (asserted in `baselines.test.ts`), and the SINGLE place the
|
|
18
|
+
* refusal is DECIDED: the create endpoint, the run-driver and the SPA's excluded-kind note all
|
|
19
|
+
* read this one value rather than each carrying its own copy.
|
|
20
|
+
*
|
|
21
|
+
* A code rather than the sentence itself because the two readers need different text in
|
|
22
|
+
* different languages: `sandboxAdmission.ts` turns it into the API refusal an operator sees, and
|
|
23
|
+
* the SPA maps it to a translated line under the field. Prose here could only ever reach the
|
|
24
|
+
* browser in English.
|
|
25
|
+
*/
|
|
26
|
+
unsupportedReason: SandboxUnsupportedReason | null;
|
|
13
27
|
/** Which rubric the judge grades this kind's output against. */
|
|
14
28
|
rubric: SandboxTaskType;
|
|
15
29
|
/**
|
|
@@ -29,18 +43,33 @@ export interface SandboxAgentKindMeta {
|
|
|
29
43
|
export declare const SANDBOX_AGENT_KINDS: readonly SandboxAgentKindMeta[];
|
|
30
44
|
/** Metadata for a testable agent kind, or undefined if the kind is not in the catalog. */
|
|
31
45
|
export declare function sandboxKindMeta(agentKind: string): SandboxAgentKindMeta | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Whether a cell for this kind must TELL the candidate it has no checkout.
|
|
48
|
+
*
|
|
49
|
+
* True exactly for a kind production dispatches into a container but the Sandbox runs inline: its
|
|
50
|
+
* composed system prompt was written for an agent holding a real clone and instructs it to diff the
|
|
51
|
+
* branch and read the changed files. Left unsaid, the candidate is graded on failing to do
|
|
52
|
+
* something impossible, which is the same defect as silently dropping a capability the prompt
|
|
53
|
+
* promised. Derived from the two declared facts rather than carried as a third one they could
|
|
54
|
+
* contradict.
|
|
55
|
+
*/
|
|
56
|
+
export declare function statesMissingCheckout(meta: SandboxAgentKindMeta): boolean;
|
|
32
57
|
/**
|
|
33
58
|
* The current shipped system-prompt text + `id@vN` label for a catalog kind.
|
|
34
59
|
*
|
|
35
|
-
* The text is the
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* workspace revision interchangeable
|
|
39
|
-
* prompt can be dropped into a matrix, with no reinterpretation of what the text means.
|
|
60
|
+
* The text is `shippedBasePromptFor`: the SAME unit a workspace prompt override holds and the
|
|
61
|
+
* pipeline builder's editor shows, deliberately WITHOUT the surface directives, trait guidance or
|
|
62
|
+
* (for a bespoke kind) the directives half the platform re-appends. That is what makes a sandbox
|
|
63
|
+
* version and a workspace revision interchangeable: a candidate can be promoted to the live prompt,
|
|
64
|
+
* and a live prompt can be dropped into a matrix, with no reinterpretation of what the text means.
|
|
65
|
+
*
|
|
66
|
+
* `PROMPT_VERSIONS` supplies only the LABEL. Reading the text off it instead was wrong for exactly
|
|
67
|
+
* the inline ENGINE kinds: `PROMPT_VERSIONS['requirement-review'].text` is the COMPOSED prompt
|
|
68
|
+
* (role plus directives), so a candidate cloned from it already carried the directives, and
|
|
69
|
+
* promoting that candidate to the live prompt doubled them.
|
|
40
70
|
*
|
|
41
|
-
* The directives are re-applied at RUN time
|
|
42
|
-
*
|
|
43
|
-
* be sent. Storing the composed text instead would double the guidance the moment it was promoted.
|
|
71
|
+
* The directives are re-applied at RUN time by `composedSystemPromptFor`, the same composition
|
|
72
|
+
* production dispatch uses, so a candidate is still graded on what would actually be sent.
|
|
44
73
|
*/
|
|
45
74
|
export declare function baselinePromptText(meta: SandboxAgentKindMeta, registry: AgentKindRegistry): {
|
|
46
75
|
text: string;
|
package/dist/baselines.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"baselines.d.ts","sourceRoot":"","sources":["../src/baselines.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"baselines.d.ts","sourceRoot":"","sources":["../src/baselines.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,EACd,wBAAwB,EACzB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAgBnD,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,wBAAwB,EAAE,CAAA;AAE5E,MAAM,WAAW,oBAAoB;IACnC,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAA;IACjB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAA;IACb,2CAA2C;IAC3C,MAAM,EAAE,kBAAkB,CAAA;IAC1B,8FAA8F;IAC9F,UAAU,EAAE,cAAc,CAAA;IAC1B;;;;;;;;;;OAUG;IACH,iBAAiB,EAAE,wBAAwB,GAAG,IAAI,CAAA;IAClD,gEAAgE;IAChE,MAAM,EAAE,eAAe,CAAA;IACvB;;;;OAIG;IACH,YAAY,EAAE,SAAS,kBAAkB,EAAE,CAAA;IAC3C;;;;OAIG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,4FAA4F;AAC5F,eAAO,MAAM,mBAAmB,EAAE,SAAS,oBAAoB,EAwG9D,CAAA;AAMD,0FAA0F;AAC1F,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAEnF;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAEzE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,oBAAoB,EAC1B,QAAQ,EAAE,iBAAiB,GAC1B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAWjC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,oBAAoB,EAAE,CAmB9F"}
|
package/dist/baselines.js
CHANGED
|
@@ -1,51 +1,105 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PROMPT_VERSIONS, promptVersionLabel, shippedBasePromptFor } from '@cat-factory/agents';
|
|
2
2
|
/** The testable-kind catalog. Ordered for stable display (inline-first, then container). */
|
|
3
3
|
export const SANDBOX_AGENT_KINDS = [
|
|
4
4
|
{
|
|
5
5
|
agentKind: 'requirements-review',
|
|
6
6
|
label: 'Requirements review',
|
|
7
7
|
bucket: 'inline',
|
|
8
|
+
sandboxRun: 'inline',
|
|
9
|
+
unsupportedReason: null,
|
|
8
10
|
rubric: 'requirement-review',
|
|
9
11
|
fixtureKinds: ['requirements'],
|
|
10
12
|
basePromptId: 'requirement-review',
|
|
11
13
|
},
|
|
12
14
|
{
|
|
15
|
+
// Bug-report triage, graded on `bug-triage` rather than `requirement-review`. The two share an
|
|
16
|
+
// output shape and nothing else: a triage's best moves are splitting conflated symptoms and
|
|
17
|
+
// asking about recovery, and `requirement-review`'s `product_scope` dimension actively docked
|
|
18
|
+
// it for the session/cookie and load-balancer hypotheses that ARE the skill here.
|
|
13
19
|
agentKind: 'clarity-review',
|
|
14
20
|
label: 'Clarity (bug-report) review',
|
|
15
21
|
bucket: 'inline',
|
|
16
|
-
|
|
22
|
+
sandboxRun: 'inline',
|
|
23
|
+
unsupportedReason: null,
|
|
24
|
+
rubric: 'bug-triage',
|
|
17
25
|
fixtureKinds: ['clarity'],
|
|
18
26
|
basePromptId: 'clarity-review',
|
|
19
27
|
},
|
|
28
|
+
{
|
|
29
|
+
// The Requirement Writer: for each requirements-review finding it recommends a concrete answer
|
|
30
|
+
// and self-reports `groundedIn` + `confidence`. Those two fields are what an UNATTENDED run
|
|
31
|
+
// acts on (ADR 0053), which is why they get rubric dimensions of their own.
|
|
32
|
+
//
|
|
33
|
+
// Driven by `IterativeReviewService` as an inline engine kind (see
|
|
34
|
+
// `INLINE_ENGINE_SYSTEM_PROMPTS`), so its baseline is the numbered `requirement-writer` prompt.
|
|
35
|
+
agentKind: 'requirements-writer',
|
|
36
|
+
label: 'Requirement writer (recommended answers)',
|
|
37
|
+
bucket: 'inline',
|
|
38
|
+
sandboxRun: 'inline',
|
|
39
|
+
unsupportedReason: null,
|
|
40
|
+
rubric: 'answer-recommendation',
|
|
41
|
+
fixtureKinds: ['answer-recommendation'],
|
|
42
|
+
basePromptId: 'requirement-writer',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
// Predictive triage: three 0..1 axes plus a rationale, run inline before any design work. Its
|
|
46
|
+
// scores gate the expensive consensus path and surface on the card, so calibration is the
|
|
47
|
+
// product behaviour under test. No numbered baseline prompt: the role text is read live.
|
|
48
|
+
agentKind: 'task-estimator',
|
|
49
|
+
label: 'Task estimator (triage scores)',
|
|
50
|
+
bucket: 'inline',
|
|
51
|
+
sandboxRun: 'inline',
|
|
52
|
+
unsupportedReason: null,
|
|
53
|
+
rubric: 'estimation',
|
|
54
|
+
fixtureKinds: ['estimation'],
|
|
55
|
+
basePromptId: null,
|
|
56
|
+
},
|
|
20
57
|
{
|
|
21
58
|
// The code `reviewer` is the coder's COMPANION, and a companion's prompt wins over every
|
|
22
59
|
// built-in track (`baseSystemPromptFor`), so its baseline is NOT the numbered `review`
|
|
23
60
|
// phase prompt — naming that id here showed a candidate the wrong text to fork from and
|
|
24
61
|
// graded it against a baseline production never sends. No numbered baseline prompt: the
|
|
25
62
|
// text is read live from the companion track, exactly like `architect-companion` below.
|
|
63
|
+
//
|
|
64
|
+
// `bucket: 'container'` is the truth: in production this companion clones the producer's PR
|
|
65
|
+
// branch and reads the real files (`isContainerBackedCompanion`), and its composed system
|
|
66
|
+
// prompt says so. The Sandbox still runs it inline, so the run-driver STATES the missing
|
|
67
|
+
// checkout in the task input and the fixture hands the change over as injected context files,
|
|
68
|
+
// which is the same seam production uses for an inline caller with no filesystem.
|
|
26
69
|
agentKind: 'reviewer',
|
|
27
70
|
label: 'Code reviewer',
|
|
28
|
-
bucket: '
|
|
71
|
+
bucket: 'container',
|
|
72
|
+
sandboxRun: 'inline',
|
|
73
|
+
unsupportedReason: null,
|
|
29
74
|
rubric: 'code-review',
|
|
30
75
|
fixtureKinds: ['code-review'],
|
|
31
76
|
basePromptId: null,
|
|
32
77
|
},
|
|
33
78
|
{
|
|
34
|
-
// Reviews an `architect`'s design proposal (the architect-companion grades it).
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
// read live from `systemPromptFor('architect-companion')`.
|
|
79
|
+
// Reviews an `architect`'s design proposal (the architect-companion grades it). Graded on
|
|
80
|
+
// `architecture-review`: a design critique's whole job is the TECHNICAL layer, so
|
|
81
|
+
// `requirement-review` was the wrong rubric in the one way that mattered. No numbered
|
|
82
|
+
// baseline prompt: the text is read live from `systemPromptFor('architect-companion')`.
|
|
38
83
|
agentKind: 'architect-companion',
|
|
39
84
|
label: 'Architecture-proposal review',
|
|
40
85
|
bucket: 'inline',
|
|
41
|
-
|
|
86
|
+
sandboxRun: 'inline',
|
|
87
|
+
unsupportedReason: null,
|
|
88
|
+
rubric: 'architecture-review',
|
|
42
89
|
fixtureKinds: ['architecture'],
|
|
43
90
|
basePromptId: null,
|
|
44
91
|
},
|
|
45
92
|
{
|
|
93
|
+
// The coder's deliverable is a pushed commit, so grading it needs a real container run against
|
|
94
|
+
// a seed repository the deployment owns; an inline cell can only grade text. Stated as that
|
|
95
|
+
// specific route rather than "not yet supported" because the alternatives are genuinely
|
|
96
|
+
// different work and a reader deciding whether to wait needs to know which one is missing. See
|
|
97
|
+
// `docs/initiatives/sandbox-coverage-expansion.md`.
|
|
46
98
|
agentKind: 'coder',
|
|
47
99
|
label: 'Coder (implementation)',
|
|
48
100
|
bucket: 'container',
|
|
101
|
+
sandboxRun: 'unsupported',
|
|
102
|
+
unsupportedReason: 'container-run-required',
|
|
49
103
|
rubric: 'implementation',
|
|
50
104
|
fixtureKinds: ['repo-feature', 'repo-bug'],
|
|
51
105
|
basePromptId: 'build',
|
|
@@ -56,27 +110,45 @@ const BY_KIND = new Map(SANDBOX_AGENT_KINDS.map((m) => [m.agentKind, m]));
|
|
|
56
110
|
export function sandboxKindMeta(agentKind) {
|
|
57
111
|
return BY_KIND.get(agentKind);
|
|
58
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Whether a cell for this kind must TELL the candidate it has no checkout.
|
|
115
|
+
*
|
|
116
|
+
* True exactly for a kind production dispatches into a container but the Sandbox runs inline: its
|
|
117
|
+
* composed system prompt was written for an agent holding a real clone and instructs it to diff the
|
|
118
|
+
* branch and read the changed files. Left unsaid, the candidate is graded on failing to do
|
|
119
|
+
* something impossible, which is the same defect as silently dropping a capability the prompt
|
|
120
|
+
* promised. Derived from the two declared facts rather than carried as a third one they could
|
|
121
|
+
* contradict.
|
|
122
|
+
*/
|
|
123
|
+
export function statesMissingCheckout(meta) {
|
|
124
|
+
return meta.bucket === 'container' && meta.sandboxRun === 'inline';
|
|
125
|
+
}
|
|
59
126
|
/**
|
|
60
127
|
* The current shipped system-prompt text + `id@vN` label for a catalog kind.
|
|
61
128
|
*
|
|
62
|
-
* The text is the
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* workspace revision interchangeable
|
|
66
|
-
* prompt can be dropped into a matrix, with no reinterpretation of what the text means.
|
|
129
|
+
* The text is `shippedBasePromptFor`: the SAME unit a workspace prompt override holds and the
|
|
130
|
+
* pipeline builder's editor shows, deliberately WITHOUT the surface directives, trait guidance or
|
|
131
|
+
* (for a bespoke kind) the directives half the platform re-appends. That is what makes a sandbox
|
|
132
|
+
* version and a workspace revision interchangeable: a candidate can be promoted to the live prompt,
|
|
133
|
+
* and a live prompt can be dropped into a matrix, with no reinterpretation of what the text means.
|
|
134
|
+
*
|
|
135
|
+
* `PROMPT_VERSIONS` supplies only the LABEL. Reading the text off it instead was wrong for exactly
|
|
136
|
+
* the inline ENGINE kinds: `PROMPT_VERSIONS['requirement-review'].text` is the COMPOSED prompt
|
|
137
|
+
* (role plus directives), so a candidate cloned from it already carried the directives, and
|
|
138
|
+
* promoting that candidate to the live prompt doubled them.
|
|
67
139
|
*
|
|
68
|
-
* The directives are re-applied at RUN time
|
|
69
|
-
*
|
|
70
|
-
* be sent. Storing the composed text instead would double the guidance the moment it was promoted.
|
|
140
|
+
* The directives are re-applied at RUN time by `composedSystemPromptFor`, the same composition
|
|
141
|
+
* production dispatch uses, so a candidate is still graded on what would actually be sent.
|
|
71
142
|
*/
|
|
72
143
|
export function baselinePromptText(meta, registry) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
144
|
+
const versioned = meta.basePromptId && meta.basePromptId in PROMPT_VERSIONS
|
|
145
|
+
? PROMPT_VERSIONS[meta.basePromptId]
|
|
146
|
+
: undefined;
|
|
77
147
|
return {
|
|
78
|
-
text:
|
|
79
|
-
label:
|
|
148
|
+
text: shippedBasePromptFor(meta.agentKind, registry),
|
|
149
|
+
label: versioned
|
|
150
|
+
? promptVersionLabel(versioned.id, versioned.version)
|
|
151
|
+
: promptVersionLabel(meta.agentKind, 1),
|
|
80
152
|
};
|
|
81
153
|
}
|
|
82
154
|
/**
|
package/dist/baselines.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"baselines.js","sourceRoot":"","sources":["../src/baselines.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"baselines.js","sourceRoot":"","sources":["../src/baselines.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { SandboxExpectation } from '@cat-factory/contracts';
|
|
2
|
+
/** An expectation is "high-impact" (a serious miss) at or above this impact rating. */
|
|
3
|
+
export declare const HIGH_IMPACT_THRESHOLD = 4;
|
|
4
|
+
/** An expectation is "tricky" (its catch earns the wow bonus) at or above this rating. */
|
|
5
|
+
export declare const TRICKY_THRESHOLD = 4;
|
|
6
|
+
export interface ExpectationScore {
|
|
7
|
+
/** Expectations the candidate output surfaced. */
|
|
8
|
+
caught: SandboxExpectation[];
|
|
9
|
+
/** Expectations the candidate output missed. */
|
|
10
|
+
missed: SandboxExpectation[];
|
|
11
|
+
/**
|
|
12
|
+
* Impact-weighted recall in [0,1]: `1 − Σ(impact of missed) / Σ(impact of all)`. Missing
|
|
13
|
+
* a high-impact item moves this far more than missing a low-impact one, which is the asymmetry the
|
|
14
|
+
* fixtures are graded on. 1 when there are no expectations.
|
|
15
|
+
*/
|
|
16
|
+
impactRecall: number;
|
|
17
|
+
/**
|
|
18
|
+
* Trickiness-weighted "wow" bonus in [0,1]: `Σ(trickiness of caught tricky items) /
|
|
19
|
+
* Σ(trickiness of all tricky items)`. Only the genuinely tricky items (trickiness ≥
|
|
20
|
+
* {@link TRICKY_THRESHOLD}) contribute, so catching a hard-to-spot finding is rewarded
|
|
21
|
+
* while missing one is not penalized here (impact handles penalties). 1 when nothing is
|
|
22
|
+
* tricky (no wow on offer).
|
|
23
|
+
*/
|
|
24
|
+
wowBonus: number;
|
|
25
|
+
/** Ids of missed expectations with impact ≥ {@link HIGH_IMPACT_THRESHOLD}. */
|
|
26
|
+
missedHighImpact: string[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Deterministic, asymmetric objective score for `findings` fixtures. An expectation is
|
|
30
|
+
* "caught" when any of its `matchHints` (defaulting to its `summary`) appears in the
|
|
31
|
+
* candidate output as a contiguous run of word tokens (case, whitespace and punctuation
|
|
32
|
+
* insensitive), so `reset logic` does not match inside `preset logic`. Recorded ALONGSIDE
|
|
33
|
+
* the judge grade (never blended in); it intentionally does not penalize extra findings
|
|
34
|
+
* (that is the judge's `false_positives` dimension). The two signals are deliberately
|
|
35
|
+
* different: `impactRecall` punishes missing what matters, `wowBonus` rewards catching what
|
|
36
|
+
* is hard to spot. See {@link SandboxExpectation}.
|
|
37
|
+
*/
|
|
38
|
+
export declare function scoreExpectations(expectations: readonly SandboxExpectation[], output: string): ExpectationScore;
|
|
39
|
+
/**
|
|
40
|
+
* Render the graded expectations into a Markdown section to append to the judge prompt:
|
|
41
|
+
* "what the judge should expect to see", with the scoring guidance the asymmetry implies.
|
|
42
|
+
* Returns an empty string when there are no expectations (an un-graded fixture).
|
|
43
|
+
*/
|
|
44
|
+
export declare function renderExpectationBrief(expectations: readonly SandboxExpectation[]): string;
|
|
45
|
+
//# sourceMappingURL=expectations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expectations.d.ts","sourceRoot":"","sources":["../src/expectations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAQhE,uFAAuF;AACvF,eAAO,MAAM,qBAAqB,IAAI,CAAA;AACtC,0FAA0F;AAC1F,eAAO,MAAM,gBAAgB,IAAI,CAAA;AAEjC,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,MAAM,EAAE,kBAAkB,EAAE,CAAA;IAC5B,gDAAgD;IAChD,MAAM,EAAE,kBAAkB,EAAE,CAAA;IAC5B;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,8EAA8E;IAC9E,gBAAgB,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,SAAS,kBAAkB,EAAE,EAC3C,MAAM,EAAE,MAAM,GACb,gBAAgB,CAwBlB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,CAgB1F"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// The deterministic, asymmetric OBJECTIVE scorer for `findings` fixtures, and the judge brief it
|
|
2
|
+
// shares its grading model with. Split from `rubrics.ts` because the two answer different
|
|
3
|
+
// questions: a rubric is what the JUDGE model scores, this is what the platform COMPUTES from the
|
|
4
|
+
// candidate text with no model in the loop. The two signals are recorded side by side and never
|
|
5
|
+
// blended (see `SandboxGrade.objective`).
|
|
6
|
+
/** An expectation is "high-impact" (a serious miss) at or above this impact rating. */
|
|
7
|
+
export const HIGH_IMPACT_THRESHOLD = 4;
|
|
8
|
+
/** An expectation is "tricky" (its catch earns the wow bonus) at or above this rating. */
|
|
9
|
+
export const TRICKY_THRESHOLD = 4;
|
|
10
|
+
/**
|
|
11
|
+
* Deterministic, asymmetric objective score for `findings` fixtures. An expectation is
|
|
12
|
+
* "caught" when any of its `matchHints` (defaulting to its `summary`) appears in the
|
|
13
|
+
* candidate output as a contiguous run of word tokens (case, whitespace and punctuation
|
|
14
|
+
* insensitive), so `reset logic` does not match inside `preset logic`. Recorded ALONGSIDE
|
|
15
|
+
* the judge grade (never blended in); it intentionally does not penalize extra findings
|
|
16
|
+
* (that is the judge's `false_positives` dimension). The two signals are deliberately
|
|
17
|
+
* different: `impactRecall` punishes missing what matters, `wowBonus` rewards catching what
|
|
18
|
+
* is hard to spot. See {@link SandboxExpectation}.
|
|
19
|
+
*/
|
|
20
|
+
export function scoreExpectations(expectations, output) {
|
|
21
|
+
const haystack = tokenize(output);
|
|
22
|
+
const caught = [];
|
|
23
|
+
const missed = [];
|
|
24
|
+
for (const expectation of expectations) {
|
|
25
|
+
const hints = expectation.matchHints.length > 0 ? expectation.matchHints : [expectation.summary];
|
|
26
|
+
const hit = hints.some((hint) => matchesHint(haystack, hint));
|
|
27
|
+
(hit ? caught : missed).push(expectation);
|
|
28
|
+
}
|
|
29
|
+
const totalImpact = expectations.reduce((sum, e) => sum + e.impact, 0);
|
|
30
|
+
const missedImpact = missed.reduce((sum, e) => sum + e.impact, 0);
|
|
31
|
+
const impactRecall = totalImpact === 0 ? 1 : round2(1 - missedImpact / totalImpact);
|
|
32
|
+
const trickyTotal = expectations
|
|
33
|
+
.filter((e) => e.trickiness >= TRICKY_THRESHOLD)
|
|
34
|
+
.reduce((sum, e) => sum + e.trickiness, 0);
|
|
35
|
+
const trickyCaught = caught
|
|
36
|
+
.filter((e) => e.trickiness >= TRICKY_THRESHOLD)
|
|
37
|
+
.reduce((sum, e) => sum + e.trickiness, 0);
|
|
38
|
+
const wowBonus = trickyTotal === 0 ? 1 : round2(trickyCaught / trickyTotal);
|
|
39
|
+
const missedHighImpact = missed.filter((e) => e.impact >= HIGH_IMPACT_THRESHOLD).map((e) => e.id);
|
|
40
|
+
return { caught, missed, impactRecall, wowBonus, missedHighImpact };
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Render the graded expectations into a Markdown section to append to the judge prompt:
|
|
44
|
+
* "what the judge should expect to see", with the scoring guidance the asymmetry implies.
|
|
45
|
+
* Returns an empty string when there are no expectations (an un-graded fixture).
|
|
46
|
+
*/
|
|
47
|
+
export function renderExpectationBrief(expectations) {
|
|
48
|
+
if (expectations.length === 0)
|
|
49
|
+
return '';
|
|
50
|
+
const lines = [
|
|
51
|
+
'## Expected findings (grading reference)',
|
|
52
|
+
'',
|
|
53
|
+
'A strong response should surface the following. Each is rated by **impact** (how bad it',
|
|
54
|
+
'is to miss, 1–5) and **trickiness** (how hard it is to spot, 1–5). Reward catching',
|
|
55
|
+
'high-trickiness items — those are the impressive catches. Penalize missing high-impact',
|
|
56
|
+
'items most heavily; missing a merely tricky item is a smaller concern.',
|
|
57
|
+
'',
|
|
58
|
+
];
|
|
59
|
+
for (const e of expectations) {
|
|
60
|
+
lines.push(`- **${e.summary}** _(impact ${e.impact}, trickiness ${e.trickiness})_`);
|
|
61
|
+
if (e.detail.trim())
|
|
62
|
+
lines.push(` - ${e.detail.trim()}`);
|
|
63
|
+
}
|
|
64
|
+
return lines.join('\n');
|
|
65
|
+
}
|
|
66
|
+
/** Round to 2 decimal places. */
|
|
67
|
+
function round2(n) {
|
|
68
|
+
return Math.round(n * 100) / 100;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Whether one hint matches the tokenized output.
|
|
72
|
+
*
|
|
73
|
+
* A trailing `*` makes the hint's LAST token match by prefix, so `idempoten*` catches
|
|
74
|
+
* "idempotent", "idempotency" and "idempotently" from one hint. Without it, matching is token
|
|
75
|
+
* EQUALITY throughout, which is why a bare stem is a dead hint: `idempoten` is not the token
|
|
76
|
+
* `idempotent`, so it scores "missed" for every answer forever while looking entirely reasonable
|
|
77
|
+
* in the fixture. The wildcard is explicit rather than inferred from a token's length, because a
|
|
78
|
+
* heuristic would also silently loosen the deliberate whole-word hints (`Map`, `atomic`) that
|
|
79
|
+
* carry the opposite intent.
|
|
80
|
+
*/
|
|
81
|
+
function matchesHint(haystack, hint) {
|
|
82
|
+
const needle = tokenize(hint);
|
|
83
|
+
if (needle.length === 0)
|
|
84
|
+
return false;
|
|
85
|
+
return containsSequence(haystack, needle, hint.trimEnd().endsWith('*'));
|
|
86
|
+
}
|
|
87
|
+
/** Lowercase alphanumeric word tokens (drops punctuation/whitespace). */
|
|
88
|
+
function tokenize(text) {
|
|
89
|
+
return text.toLowerCase().match(/[a-z0-9]+/g) ?? [];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Whether `needle`'s tokens appear as a contiguous run within `haystack`'s tokens. With
|
|
93
|
+
* `prefixTail`, the final needle token need only be a PREFIX of the token it lands on.
|
|
94
|
+
*/
|
|
95
|
+
function containsSequence(haystack, needle, prefixTail = false) {
|
|
96
|
+
if (needle.length === 0)
|
|
97
|
+
return false;
|
|
98
|
+
const last = needle.length - 1;
|
|
99
|
+
for (let i = 0; i + needle.length <= haystack.length; i++) {
|
|
100
|
+
let hit = true;
|
|
101
|
+
for (let j = 0; j < needle.length; j++) {
|
|
102
|
+
const token = haystack[i + j] ?? '';
|
|
103
|
+
const matched = prefixTail && j === last ? token.startsWith(needle[j] ?? '') : token === needle[j];
|
|
104
|
+
if (!matched) {
|
|
105
|
+
hit = false;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (hit)
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=expectations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expectations.js","sourceRoot":"","sources":["../src/expectations.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { type SandboxTaskType, type Rubric, type RubricDimension,
|
|
2
|
-
export { type
|
|
1
|
+
export { type SandboxTaskType, type Rubric, type RubricDimension, SANDBOX_TASK_TYPES, rubricFor, weightedTotal, } from './rubrics.js';
|
|
2
|
+
export { type ExpectationScore, HIGH_IMPACT_THRESHOLD, TRICKY_THRESHOLD, scoreExpectations, renderExpectationBrief, } from './expectations.js';
|
|
3
|
+
export { type SandboxAgentBucket, type SandboxAgentKindMeta, type SandboxRunMode, SANDBOX_AGENT_KINDS, sandboxKindMeta, statesMissingCheckout, baselinePromptText, listBaselines, } from './baselines.js';
|
|
3
4
|
export { type NewVersionFields, firstVersionFromBaseline, nextVersion, versionLabel, filterByLabels, } from './promptVersions.logic.js';
|
|
4
5
|
export { workspacePromptVersionId, workspacePromptLineageId, parseWorkspacePromptVersionId, workspacePromptVersions, sandboxPromptKinds, } from './workspacePrompts.js';
|
|
5
6
|
export { type ExpandDeps, cellCount, expandMatrix, isRunnableMatrix } from './matrix.logic.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,MAAM,EACX,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,MAAM,EACX,KAAK,eAAe,EACpB,kBAAkB,EAClB,SAAS,EACT,aAAa,GACd,MAAM,cAAc,CAAA;AAErB,OAAO,EACL,KAAK,gBAAgB,EACrB,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,GACd,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EACL,KAAK,gBAAgB,EACrB,wBAAwB,EACxB,WAAW,EACX,YAAY,EACZ,cAAc,GACf,MAAM,2BAA2B,CAAA;AAElC,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,6BAA6B,EAC7B,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAE,KAAK,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAE9F,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,EAC7B,wBAAwB,EACxB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,eAAe,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
// agents (baseline prompts), and nothing in the core product depends on it, so the
|
|
4
4
|
// whole feature can be lifted out later. This entry re-exports the pure domain logic;
|
|
5
5
|
// the run driver + judge service (which consume the executor seams) build on top.
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
6
|
+
export { SANDBOX_TASK_TYPES, rubricFor, weightedTotal, } from './rubrics.js';
|
|
7
|
+
export { HIGH_IMPACT_THRESHOLD, TRICKY_THRESHOLD, scoreExpectations, renderExpectationBrief, } from './expectations.js';
|
|
8
|
+
export { SANDBOX_AGENT_KINDS, sandboxKindMeta, statesMissingCheckout, baselinePromptText, listBaselines, } from './baselines.js';
|
|
8
9
|
export { firstVersionFromBaseline, nextVersion, versionLabel, filterByLabels, } from './promptVersions.logic.js';
|
|
9
10
|
export { workspacePromptVersionId, workspacePromptLineageId, parseWorkspacePromptVersionId, workspacePromptVersions, sandboxPromptKinds, } from './workspacePrompts.js';
|
|
10
11
|
export { cellCount, expandMatrix, isRunnableMatrix } from './matrix.logic.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,kFAAkF;AAClF,mFAAmF;AACnF,sFAAsF;AACtF,kFAAkF;AAElF,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,kFAAkF;AAClF,mFAAmF;AACnF,sFAAsF;AACtF,kFAAkF;AAElF,OAAO,EAIL,kBAAkB,EAClB,SAAS,EACT,aAAa,GACd,MAAM,cAAc,CAAA;AAErB,OAAO,EAEL,qBAAqB,EACrB,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EAIL,mBAAmB,EACnB,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,GACd,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAEL,wBAAwB,EACxB,WAAW,EACX,YAAY,EACZ,cAAc,GACf,MAAM,2BAA2B,CAAA;AAElC,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,6BAA6B,EAC7B,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAAmB,SAAS,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAE9F,OAAO,EAIL,wBAAwB,EACxB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,eAAe,CAAA"}
|
package/dist/rubrics.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The grading task a Sandbox agent kind maps to (drives which rubric is used).
|
|
3
|
+
*
|
|
4
|
+
* Adding a member means adding its dimension list to {@link RUBRICS}, which is a
|
|
5
|
+
* `Record<SandboxTaskType, …>` and so fails to compile until it is there.
|
|
6
|
+
*/
|
|
7
|
+
export type SandboxTaskType = 'requirement-review' | 'code-review' | 'implementation' | 'architecture-review' | 'bug-triage' | 'estimation' | 'answer-recommendation';
|
|
4
8
|
export interface RubricDimension {
|
|
5
9
|
key: string;
|
|
6
10
|
label: string;
|
|
@@ -11,53 +15,19 @@ export interface Rubric {
|
|
|
11
15
|
task: SandboxTaskType;
|
|
12
16
|
dimensions: RubricDimension[];
|
|
13
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Every grading task the Sandbox ships, as a value.
|
|
20
|
+
*
|
|
21
|
+
* Exported so a consumer can enumerate the rubrics rather than re-listing them: the
|
|
22
|
+
* benchmark-harness conformity guard reads it to assert that every task the OFFLINE harness grades
|
|
23
|
+
* is also a Sandbox task with identical dimensions, which is a relation over a list it does not
|
|
24
|
+
* own. Derived from {@link RUBRICS} so adding a rubric extends it with no second edit.
|
|
25
|
+
*/
|
|
26
|
+
export declare const SANDBOX_TASK_TYPES: readonly SandboxTaskType[];
|
|
14
27
|
export declare function rubricFor(task: SandboxTaskType): Rubric;
|
|
15
28
|
/** Weighted mean of dimension scores (1–5), using the rubric weights. */
|
|
16
29
|
export declare function weightedTotal(task: SandboxTaskType, scores: {
|
|
17
30
|
key: string;
|
|
18
31
|
score: number;
|
|
19
32
|
}[]): number;
|
|
20
|
-
/** An expectation is "high-impact" (a serious miss) at or above this impact rating. */
|
|
21
|
-
export declare const HIGH_IMPACT_THRESHOLD = 4;
|
|
22
|
-
/** An expectation is "tricky" (its catch earns the wow bonus) at or above this rating. */
|
|
23
|
-
export declare const TRICKY_THRESHOLD = 4;
|
|
24
|
-
export interface ExpectationScore {
|
|
25
|
-
/** Expectations the candidate output surfaced. */
|
|
26
|
-
caught: SandboxExpectation[];
|
|
27
|
-
/** Expectations the candidate output missed. */
|
|
28
|
-
missed: SandboxExpectation[];
|
|
29
|
-
/**
|
|
30
|
-
* Impact-weighted recall in [0,1]: `1 − Σ(impact of missed) / Σ(impact of all)`. Missing
|
|
31
|
-
* a high-impact item moves this far more than missing a low-impact one — the asymmetry the
|
|
32
|
-
* fixtures are graded on. 1 when there are no expectations.
|
|
33
|
-
*/
|
|
34
|
-
impactRecall: number;
|
|
35
|
-
/**
|
|
36
|
-
* Trickiness-weighted "wow" bonus in [0,1]: `Σ(trickiness of caught tricky items) /
|
|
37
|
-
* Σ(trickiness of all tricky items)`. Only the genuinely tricky items (trickiness ≥
|
|
38
|
-
* {@link TRICKY_THRESHOLD}) contribute, so catching a hard-to-spot finding is rewarded
|
|
39
|
-
* while missing one is not penalized here (impact handles penalties). 1 when nothing is
|
|
40
|
-
* tricky (no wow on offer).
|
|
41
|
-
*/
|
|
42
|
-
wowBonus: number;
|
|
43
|
-
/** Ids of missed expectations with impact ≥ {@link HIGH_IMPACT_THRESHOLD}. */
|
|
44
|
-
missedHighImpact: string[];
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Deterministic, asymmetric objective score for `findings` fixtures. An expectation is
|
|
48
|
-
* "caught" when any of its `matchHints` (defaulting to its `summary`) appears in the
|
|
49
|
-
* candidate output as a contiguous run of word tokens — case/whitespace/punctuation
|
|
50
|
-
* insensitive, so `reset logic` does not match inside `preset logic`. Recorded ALONGSIDE
|
|
51
|
-
* the judge grade (never blended in); it intentionally does not penalize extra findings
|
|
52
|
-
* (that is the judge's `false_positives` dimension). The two signals are deliberately
|
|
53
|
-
* different: `impactRecall` punishes missing what matters, `wowBonus` rewards catching what
|
|
54
|
-
* is hard to spot. See {@link SandboxExpectation}.
|
|
55
|
-
*/
|
|
56
|
-
export declare function scoreExpectations(expectations: readonly SandboxExpectation[], output: string): ExpectationScore;
|
|
57
|
-
/**
|
|
58
|
-
* Render the graded expectations into a Markdown section to append to the judge prompt —
|
|
59
|
-
* "what the judge should expect to see", with the scoring guidance the asymmetry implies.
|
|
60
|
-
* Returns an empty string when there are no expectations (an un-graded fixture).
|
|
61
|
-
*/
|
|
62
|
-
export declare function renderExpectationBrief(expectations: readonly SandboxExpectation[]): string;
|
|
63
33
|
//# sourceMappingURL=rubrics.d.ts.map
|
package/dist/rubrics.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rubrics.d.ts","sourceRoot":"","sources":["../src/rubrics.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rubrics.d.ts","sourceRoot":"","sources":["../src/rubrics.ts"],"names":[],"mappings":"AAgBA;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GACvB,oBAAoB,GACpB,aAAa,GACb,gBAAgB,GAChB,qBAAqB,GACrB,YAAY,GACZ,YAAY,GACZ,uBAAuB,CAAA;AAE3B,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,eAAe,CAAA;IACrB,UAAU,EAAE,eAAe,EAAE,CAAA;CAC9B;AAkVD;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,EAA2B,SAAS,eAAe,EAAE,CAAA;AAEpF,wBAAgB,SAAS,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAEvD;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAC3B,IAAI,EAAE,eAAe,EACrB,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,GACvC,MAAM,CAYR"}
|
package/dist/rubrics.js
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
// Grading rubrics for the Sandbox judge. Reference-free: each dimension is scored 1–5 by the
|
|
2
|
+
// judge model against the task input + the candidate output; the weighted mean is the cell score.
|
|
3
|
+
//
|
|
4
|
+
// The first three (`requirement-review`, `code-review`, `implementation`) are lifted verbatim from
|
|
5
|
+
// the benchmark harness's rubrics (`backend/internal/benchmark-harness/src/rubrics.ts`) so the
|
|
6
|
+
// in-product Sandbox and the offline `cat-bench` grade on the same axes. Those copies are pinned
|
|
7
|
+
// equal by `benchmark-harness/test/rubrics.conformity.test.ts`, which also asserts every harness
|
|
8
|
+
// task IS a Sandbox task: a dimension added to one side and not the other does not fail anything on
|
|
9
|
+
// its own, it just quietly makes a Sandbox score and a benchmark score incomparable. Change one,
|
|
10
|
+
// change both.
|
|
11
|
+
//
|
|
12
|
+
// The remaining rubrics are Sandbox-only, because the offline harness has no runner for them. They
|
|
13
|
+
// exist because a rubric is a claim about what the task IS: grading an architecture critique or a
|
|
14
|
+
// bug triage on `requirement-review` scored them against `product_scope`, a dimension that
|
|
15
|
+
// penalizes exactly the technical findings those two stages are FOR.
|
|
1
16
|
const REQUIREMENT_REVIEW = [
|
|
2
17
|
{
|
|
3
18
|
key: 'gap_coverage',
|
|
@@ -107,11 +122,209 @@ const IMPLEMENTATION = [
|
|
|
107
122
|
weight: 1,
|
|
108
123
|
},
|
|
109
124
|
];
|
|
125
|
+
// A design critique is the OPPOSITE of a requirements review on the one axis that matters: the
|
|
126
|
+
// technical layer is what it is FOR. Grading it on `requirement-review` docked it for every
|
|
127
|
+
// partition-key, durability and hot-key finding, which is why the architecture fixtures'
|
|
128
|
+
// highest-value expectations were the ones the rubric punished.
|
|
129
|
+
const ARCHITECTURE_REVIEW = [
|
|
130
|
+
{
|
|
131
|
+
key: 'design_risk_detection',
|
|
132
|
+
label: 'Design-risk detection',
|
|
133
|
+
description: 'Finds the genuine correctness, scaling, consistency and durability flaws in the proposed ' +
|
|
134
|
+
'design, including the ones its own wording papers over.',
|
|
135
|
+
weight: 3,
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
key: 'failure_mode_reasoning',
|
|
139
|
+
label: 'Failure-mode reasoning',
|
|
140
|
+
description: 'Reasons about what the design does when a component dies, two writes race, delivery ' +
|
|
141
|
+
'retries or load is uneven, rather than only assessing the happy path.',
|
|
142
|
+
weight: 3,
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
key: 'tradeoff_grounding',
|
|
146
|
+
label: 'Trade-off grounding',
|
|
147
|
+
description: 'Weighs the proposal against concrete alternatives and says what each one buys and costs, ' +
|
|
148
|
+
'instead of asserting a preference.',
|
|
149
|
+
weight: 2,
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
key: 'operability',
|
|
153
|
+
label: 'Operability',
|
|
154
|
+
description: 'Covers what running this actually needs: rollout and migration, what is observable, the ' +
|
|
155
|
+
'cost shape, and what a person would be paged for.',
|
|
156
|
+
weight: 1,
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
key: 'actionability',
|
|
160
|
+
label: 'Actionability',
|
|
161
|
+
description: 'Each finding names the part of the design it concerns and what to change; no generic ' +
|
|
162
|
+
'architecture advice that would apply to any proposal.',
|
|
163
|
+
weight: 2,
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
key: 'false_positives',
|
|
167
|
+
label: 'Few false positives',
|
|
168
|
+
description: 'Does not invent flaws or demand scale the stated context does not need, and says plainly ' +
|
|
169
|
+
'where a choice is sound.',
|
|
170
|
+
weight: 2,
|
|
171
|
+
},
|
|
172
|
+
];
|
|
173
|
+
// Bug triage shares nothing with a requirements review except its output shape. Its whole job is
|
|
174
|
+
// to make an unactionable report diagnosable, and the two moves that decide whether it succeeded
|
|
175
|
+
// (splitting conflated symptoms, and asking about containment rather than only the fix) had no
|
|
176
|
+
// dimension of their own.
|
|
177
|
+
const BUG_TRIAGE = [
|
|
178
|
+
{
|
|
179
|
+
key: 'missing_facts',
|
|
180
|
+
label: 'Missing facts',
|
|
181
|
+
description: 'Asks for the facts that actually block a diagnosis: reproduction, scope, timing and the ' +
|
|
182
|
+
'regression window, environment, and observed versus expected behaviour.',
|
|
183
|
+
weight: 3,
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
key: 'symptom_separation',
|
|
187
|
+
label: 'Symptom separation',
|
|
188
|
+
description: 'Splits a report that conflates several distinct failures into separate issues rather ' +
|
|
189
|
+
'than triaging them as one, and names what distinguishes them.',
|
|
190
|
+
weight: 3,
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
key: 'hypothesis_quality',
|
|
194
|
+
label: 'Hypothesis quality',
|
|
195
|
+
description: 'Offers a concrete, testable cause where the evidence supports one (and says what would ' +
|
|
196
|
+
'confirm it), without guessing where it does not.',
|
|
197
|
+
weight: 2,
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
key: 'containment',
|
|
201
|
+
label: 'Blast radius & recovery',
|
|
202
|
+
description: 'Covers who is affected and how many, and whether anything lost or corrupted can be ' +
|
|
203
|
+
'recovered, rather than treating the eventual fix as the whole response.',
|
|
204
|
+
weight: 2,
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
key: 'no_redundancy',
|
|
208
|
+
label: 'No redundant questions',
|
|
209
|
+
description: 'Does not re-ask what the report or an attached investigation already answers; builds on ' +
|
|
210
|
+
'the evidence it was given.',
|
|
211
|
+
weight: 1,
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
key: 'actionability',
|
|
215
|
+
label: 'Actionability',
|
|
216
|
+
description: 'Each item is phrased so the reporter or an on-call engineer can act on it directly.',
|
|
217
|
+
weight: 2,
|
|
218
|
+
},
|
|
219
|
+
];
|
|
220
|
+
// A predictive triage returns three numbers and a paragraph, so every rubric written for prose
|
|
221
|
+
// grades it on axes it structurally cannot show. What matters instead is whether the numbers are
|
|
222
|
+
// defensible, independent of each other, and justified by something in the task.
|
|
223
|
+
const ESTIMATION = [
|
|
224
|
+
{
|
|
225
|
+
key: 'calibration',
|
|
226
|
+
label: 'Calibration',
|
|
227
|
+
description: 'The scores are defensible for the work described: neither anchored to the middle of the ' +
|
|
228
|
+
'range nor uniformly extreme.',
|
|
229
|
+
weight: 3,
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
key: 'axis_independence',
|
|
233
|
+
label: 'Axis independence',
|
|
234
|
+
description: 'Complexity, risk and impact are judged separately. A task may be intricate and safe, or ' +
|
|
235
|
+
'trivial and dangerous; three near-identical numbers need a reason.',
|
|
236
|
+
weight: 2,
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
key: 'evidence',
|
|
240
|
+
label: 'Evidence in the rationale',
|
|
241
|
+
description: 'The rationale names the specific things in the task that drive each score, rather than ' +
|
|
242
|
+
'restating the task or asserting a level.',
|
|
243
|
+
weight: 3,
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
key: 'blast_radius_reasoning',
|
|
247
|
+
label: 'Blast-radius reasoning',
|
|
248
|
+
description: 'Impact reflects who and how much is affected if the change goes wrong, not how large or ' +
|
|
249
|
+
'how difficult the change is (that is complexity).',
|
|
250
|
+
weight: 2,
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
key: 'format_compliance',
|
|
254
|
+
label: 'Format compliance',
|
|
255
|
+
description: 'Returns exactly the requested JSON object (the three numeric axes plus the rationale) ' +
|
|
256
|
+
'and nothing else: no prose, no code fences, no extra keys.',
|
|
257
|
+
weight: 1,
|
|
258
|
+
},
|
|
259
|
+
];
|
|
260
|
+
// The Requirement Writer's two self-reported fields are what an unattended run acts on (ADR 0053):
|
|
261
|
+
// a confident answer may be adopted with nobody reading it, and `groundedIn` is the provenance a
|
|
262
|
+
// human checks before trusting one. Both are claims the writer makes about itself, so both get a
|
|
263
|
+
// dimension of their own; no prose rubric scores an honest provenance report.
|
|
264
|
+
const ANSWER_RECOMMENDATION = [
|
|
265
|
+
{
|
|
266
|
+
key: 'answer_concreteness',
|
|
267
|
+
label: 'Concrete, adoptable answers',
|
|
268
|
+
description: 'Each recommendation is a specific default a product owner could accept as written, not a ' +
|
|
269
|
+
'restatement of the finding and not an "it depends".',
|
|
270
|
+
weight: 3,
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
key: 'product_scope',
|
|
274
|
+
label: 'Product scope discipline',
|
|
275
|
+
description: 'Recommends product / business decisions only (a behaviour, rule, limit or boundary), ' +
|
|
276
|
+
'never a technical design, and does not answer a technical question that slipped past the ' +
|
|
277
|
+
'reviewer as if it were one.',
|
|
278
|
+
weight: 2,
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
key: 'grounding_honesty',
|
|
282
|
+
label: 'Honest grounding',
|
|
283
|
+
description: 'Reports where each answer actually came from. A standard or the project spec is cited ' +
|
|
284
|
+
'only when it genuinely settles the finding; general knowledge is labelled as such rather ' +
|
|
285
|
+
'than dressed up as sourced.',
|
|
286
|
+
weight: 3,
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
key: 'confidence_calibration',
|
|
290
|
+
label: 'Confidence calibration',
|
|
291
|
+
description: 'Confidence reflects how sure the answer is the one THIS project would choose. High ' +
|
|
292
|
+
'confidence is reserved for answers that need nobody to sign off; anything turning on ' +
|
|
293
|
+
'unstated business specifics is rated low.',
|
|
294
|
+
weight: 3,
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
key: 'coverage',
|
|
298
|
+
label: 'Coverage',
|
|
299
|
+
description: 'Answers every finding it was given, one entry per id, with none dropped, merged or ' +
|
|
300
|
+
'invented.',
|
|
301
|
+
weight: 2,
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
key: 'concision',
|
|
305
|
+
label: 'Concision',
|
|
306
|
+
description: 'States the answer in a few sentences, without preamble, hedging or padding.',
|
|
307
|
+
weight: 1,
|
|
308
|
+
},
|
|
309
|
+
];
|
|
110
310
|
const RUBRICS = {
|
|
111
311
|
'requirement-review': REQUIREMENT_REVIEW,
|
|
112
312
|
'code-review': CODE_REVIEW,
|
|
113
313
|
implementation: IMPLEMENTATION,
|
|
314
|
+
'architecture-review': ARCHITECTURE_REVIEW,
|
|
315
|
+
'bug-triage': BUG_TRIAGE,
|
|
316
|
+
estimation: ESTIMATION,
|
|
317
|
+
'answer-recommendation': ANSWER_RECOMMENDATION,
|
|
114
318
|
};
|
|
319
|
+
/**
|
|
320
|
+
* Every grading task the Sandbox ships, as a value.
|
|
321
|
+
*
|
|
322
|
+
* Exported so a consumer can enumerate the rubrics rather than re-listing them: the
|
|
323
|
+
* benchmark-harness conformity guard reads it to assert that every task the OFFLINE harness grades
|
|
324
|
+
* is also a Sandbox task with identical dimensions, which is a relation over a list it does not
|
|
325
|
+
* own. Derived from {@link RUBRICS} so adding a rubric extends it with no second edit.
|
|
326
|
+
*/
|
|
327
|
+
export const SANDBOX_TASK_TYPES = Object.keys(RUBRICS);
|
|
115
328
|
export function rubricFor(task) {
|
|
116
329
|
return { task, dimensions: RUBRICS[task] };
|
|
117
330
|
}
|
|
@@ -129,92 +342,4 @@ export function weightedTotal(task, scores) {
|
|
|
129
342
|
}
|
|
130
343
|
return weight === 0 ? 0 : Math.round((sum / weight) * 100) / 100;
|
|
131
344
|
}
|
|
132
|
-
/** An expectation is "high-impact" (a serious miss) at or above this impact rating. */
|
|
133
|
-
export const HIGH_IMPACT_THRESHOLD = 4;
|
|
134
|
-
/** An expectation is "tricky" (its catch earns the wow bonus) at or above this rating. */
|
|
135
|
-
export const TRICKY_THRESHOLD = 4;
|
|
136
|
-
/**
|
|
137
|
-
* Deterministic, asymmetric objective score for `findings` fixtures. An expectation is
|
|
138
|
-
* "caught" when any of its `matchHints` (defaulting to its `summary`) appears in the
|
|
139
|
-
* candidate output as a contiguous run of word tokens — case/whitespace/punctuation
|
|
140
|
-
* insensitive, so `reset logic` does not match inside `preset logic`. Recorded ALONGSIDE
|
|
141
|
-
* the judge grade (never blended in); it intentionally does not penalize extra findings
|
|
142
|
-
* (that is the judge's `false_positives` dimension). The two signals are deliberately
|
|
143
|
-
* different: `impactRecall` punishes missing what matters, `wowBonus` rewards catching what
|
|
144
|
-
* is hard to spot. See {@link SandboxExpectation}.
|
|
145
|
-
*/
|
|
146
|
-
export function scoreExpectations(expectations, output) {
|
|
147
|
-
const haystack = tokenize(output);
|
|
148
|
-
const caught = [];
|
|
149
|
-
const missed = [];
|
|
150
|
-
for (const expectation of expectations) {
|
|
151
|
-
const hints = expectation.matchHints.length > 0 ? expectation.matchHints : [expectation.summary];
|
|
152
|
-
const hit = hints.some((hint) => {
|
|
153
|
-
const needle = tokenize(hint);
|
|
154
|
-
return needle.length > 0 && containsSequence(haystack, needle);
|
|
155
|
-
});
|
|
156
|
-
(hit ? caught : missed).push(expectation);
|
|
157
|
-
}
|
|
158
|
-
const totalImpact = expectations.reduce((sum, e) => sum + e.impact, 0);
|
|
159
|
-
const missedImpact = missed.reduce((sum, e) => sum + e.impact, 0);
|
|
160
|
-
const impactRecall = totalImpact === 0 ? 1 : round2(1 - missedImpact / totalImpact);
|
|
161
|
-
const trickyTotal = expectations
|
|
162
|
-
.filter((e) => e.trickiness >= TRICKY_THRESHOLD)
|
|
163
|
-
.reduce((sum, e) => sum + e.trickiness, 0);
|
|
164
|
-
const trickyCaught = caught
|
|
165
|
-
.filter((e) => e.trickiness >= TRICKY_THRESHOLD)
|
|
166
|
-
.reduce((sum, e) => sum + e.trickiness, 0);
|
|
167
|
-
const wowBonus = trickyTotal === 0 ? 1 : round2(trickyCaught / trickyTotal);
|
|
168
|
-
const missedHighImpact = missed.filter((e) => e.impact >= HIGH_IMPACT_THRESHOLD).map((e) => e.id);
|
|
169
|
-
return { caught, missed, impactRecall, wowBonus, missedHighImpact };
|
|
170
|
-
}
|
|
171
|
-
/**
|
|
172
|
-
* Render the graded expectations into a Markdown section to append to the judge prompt —
|
|
173
|
-
* "what the judge should expect to see", with the scoring guidance the asymmetry implies.
|
|
174
|
-
* Returns an empty string when there are no expectations (an un-graded fixture).
|
|
175
|
-
*/
|
|
176
|
-
export function renderExpectationBrief(expectations) {
|
|
177
|
-
if (expectations.length === 0)
|
|
178
|
-
return '';
|
|
179
|
-
const lines = [
|
|
180
|
-
'## Expected findings (grading reference)',
|
|
181
|
-
'',
|
|
182
|
-
'A strong response should surface the following. Each is rated by **impact** (how bad it',
|
|
183
|
-
'is to miss, 1–5) and **trickiness** (how hard it is to spot, 1–5). Reward catching',
|
|
184
|
-
'high-trickiness items — those are the impressive catches. Penalize missing high-impact',
|
|
185
|
-
'items most heavily; missing a merely tricky item is a smaller concern.',
|
|
186
|
-
'',
|
|
187
|
-
];
|
|
188
|
-
for (const e of expectations) {
|
|
189
|
-
lines.push(`- **${e.summary}** _(impact ${e.impact}, trickiness ${e.trickiness})_`);
|
|
190
|
-
if (e.detail.trim())
|
|
191
|
-
lines.push(` - ${e.detail.trim()}`);
|
|
192
|
-
}
|
|
193
|
-
return lines.join('\n');
|
|
194
|
-
}
|
|
195
|
-
/** Round to 2 decimal places. */
|
|
196
|
-
function round2(n) {
|
|
197
|
-
return Math.round(n * 100) / 100;
|
|
198
|
-
}
|
|
199
|
-
/** Lowercase alphanumeric word tokens (drops punctuation/whitespace). */
|
|
200
|
-
function tokenize(text) {
|
|
201
|
-
return text.toLowerCase().match(/[a-z0-9]+/g) ?? [];
|
|
202
|
-
}
|
|
203
|
-
/** Whether `needle`'s tokens appear as a contiguous run within `haystack`'s tokens. */
|
|
204
|
-
function containsSequence(haystack, needle) {
|
|
205
|
-
if (needle.length === 0)
|
|
206
|
-
return false;
|
|
207
|
-
for (let i = 0; i + needle.length <= haystack.length; i++) {
|
|
208
|
-
let hit = true;
|
|
209
|
-
for (let j = 0; j < needle.length; j++) {
|
|
210
|
-
if (haystack[i + j] !== needle[j]) {
|
|
211
|
-
hit = false;
|
|
212
|
-
break;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
if (hit)
|
|
216
|
-
return true;
|
|
217
|
-
}
|
|
218
|
-
return false;
|
|
219
|
-
}
|
|
220
345
|
//# sourceMappingURL=rubrics.js.map
|
package/dist/rubrics.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rubrics.js","sourceRoot":"","sources":["../src/rubrics.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rubrics.js","sourceRoot":"","sources":["../src/rubrics.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/sandbox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Parallel prompt/model testing surface: versioned prompt candidates, experiment matrices, judge + objective grading. Isolated from the core product so it can be extracted.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@cat-factory/agents": "0.
|
|
28
|
-
"@cat-factory/
|
|
29
|
-
"@cat-factory/
|
|
30
|
-
"@cat-factory/sandbox-fixtures": "0.
|
|
27
|
+
"@cat-factory/agents": "0.136.0",
|
|
28
|
+
"@cat-factory/contracts": "0.320.0",
|
|
29
|
+
"@cat-factory/kernel": "0.310.0",
|
|
30
|
+
"@cat-factory/sandbox-fixtures": "0.8.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"typescript": "7.0.2",
|