@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.
@@ -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 = 'inline' | 'container';
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
- /** Inline kinds run a single LLM call; container kinds need a real checkout. */
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 BASE (track) prompt, deliberately WITHOUT the surface directives and trait
36
- * guidance the platform appends. That is the same unit a workspace prompt override holds and the
37
- * same unit the pipeline builder's editor shows, which is what makes a sandbox version and a
38
- * workspace revision interchangeable a candidate can be promoted to the live prompt, and a live
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 (`SandboxRunService`, via the same `systemPromptFor`
42
- * override path production dispatch uses), so a candidate is still graded on what would actually
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;
@@ -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,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAWnD,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,WAAW,CAAA;AAEvD,MAAM,WAAW,oBAAoB;IACnC,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAA;IACjB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAA;IACb,gFAAgF;IAChF,MAAM,EAAE,kBAAkB,CAAA;IAC1B,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,EAkD9D,CAAA;AAMD,0FAA0F;AAC1F,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CAEnF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,oBAAoB,EAC1B,QAAQ,EAAE,iBAAiB,GAC1B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CASjC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,oBAAoB,EAAE,CAmB9F"}
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 { baseSystemPromptFor, PROMPT_VERSIONS, promptVersionLabel } from '@cat-factory/agents';
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
- rubric: 'requirement-review',
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: 'inline',
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). A
35
- // proposal critique is graded on the same axes as a requirements review — gap
36
- // coverage, no-hallucination, specificity. No numbered baseline prompt: the text is
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
- rubric: 'requirement-review',
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 BASE (track) prompt, deliberately WITHOUT the surface directives and trait
63
- * guidance the platform appends. That is the same unit a workspace prompt override holds and the
64
- * same unit the pipeline builder's editor shows, which is what makes a sandbox version and a
65
- * workspace revision interchangeable a candidate can be promoted to the live prompt, and a live
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 (`SandboxRunService`, via the same `systemPromptFor`
69
- * override path production dispatch uses), so a candidate is still graded on what would actually
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
- if (meta.basePromptId && meta.basePromptId in PROMPT_VERSIONS) {
74
- const versioned = PROMPT_VERSIONS[meta.basePromptId];
75
- return { text: versioned.text, label: promptVersionLabel(versioned.id, versioned.version) };
76
- }
144
+ const versioned = meta.basePromptId && meta.basePromptId in PROMPT_VERSIONS
145
+ ? PROMPT_VERSIONS[meta.basePromptId]
146
+ : undefined;
77
147
  return {
78
- text: baseSystemPromptFor(meta.agentKind, registry),
79
- label: promptVersionLabel(meta.agentKind, 1),
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
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"baselines.js","sourceRoot":"","sources":["../src/baselines.ts"],"names":[],"mappings":"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"}
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, type ExpectationScore, HIGH_IMPACT_THRESHOLD, TRICKY_THRESHOLD, rubricFor, weightedTotal, scoreExpectations, renderExpectationBrief, } from './rubrics.js';
2
- export { type SandboxAgentBucket, type SandboxAgentKindMeta, SANDBOX_AGENT_KINDS, sandboxKindMeta, baselinePromptText, listBaselines, } from './baselines.js';
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';
@@ -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,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,cAAc,CAAA;AAErB,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,mBAAmB,EACnB,eAAe,EACf,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"}
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 { HIGH_IMPACT_THRESHOLD, TRICKY_THRESHOLD, rubricFor, weightedTotal, scoreExpectations, renderExpectationBrief, } from './rubrics.js';
7
- export { SANDBOX_AGENT_KINDS, sandboxKindMeta, baselinePromptText, listBaselines, } from './baselines.js';
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,EAKL,qBAAqB,EACrB,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,cAAc,CAAA;AAErB,OAAO,EAGL,mBAAmB,EACnB,eAAe,EACf,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"}
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
- import type { SandboxExpectation } from '@cat-factory/contracts';
2
- /** The grading task a Sandbox agent kind maps to (drives which rubric is used). */
3
- export type SandboxTaskType = 'requirement-review' | 'code-review' | 'implementation';
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
@@ -1 +1 @@
1
- {"version":3,"file":"rubrics.d.ts","sourceRoot":"","sources":["../src/rubrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAYhE,mFAAmF;AACnF,MAAM,MAAM,eAAe,GAAG,oBAAoB,GAAG,aAAa,GAAG,gBAAgB,CAAA;AAErF,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;AA2HD,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;AAED,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,CA2BlB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,CAgB1F"}
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
@@ -1 +1 @@
1
- {"version":3,"file":"rubrics.js","sourceRoot":"","sources":["../src/rubrics.ts"],"names":[],"mappings":"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"}
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.11.162",
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.135.0",
28
- "@cat-factory/kernel": "0.309.0",
29
- "@cat-factory/contracts": "0.319.0",
30
- "@cat-factory/sandbox-fixtures": "0.7.361"
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",