@sanity/ailf 4.5.0 → 5.0.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.
Files changed (139) hide show
  1. package/canonical/grader-references/agent-harness-tools.yaml +42 -0
  2. package/canonical/grader-references/knowledge-probe-recall.yaml +36 -0
  3. package/canonical/grader-references/mcp-server-spec.yaml +51 -0
  4. package/canonical/grader-references/portable-text.yaml +48 -0
  5. package/config/rubrics.ts +38 -2
  6. package/dist/_vendor/ailf-core/artifact-registry.d.ts +197 -2
  7. package/dist/_vendor/ailf-core/artifact-registry.js +419 -5
  8. package/dist/_vendor/ailf-core/examples/index.d.ts +125 -26
  9. package/dist/_vendor/ailf-core/examples/index.js +146 -47
  10. package/dist/_vendor/ailf-core/ports/context.d.ts +26 -0
  11. package/dist/_vendor/ailf-core/ports/index.d.ts +2 -0
  12. package/dist/_vendor/ailf-core/ports/index.js +1 -0
  13. package/dist/_vendor/ailf-core/ports/llm-client.d.ts +112 -0
  14. package/dist/_vendor/ailf-core/ports/llm-client.js +68 -0
  15. package/dist/_vendor/ailf-core/ports/mode-handler.d.ts +15 -0
  16. package/dist/_vendor/ailf-core/schemas/branded-string.d.ts +40 -0
  17. package/dist/_vendor/ailf-core/schemas/branded-string.js +45 -0
  18. package/dist/_vendor/ailf-core/schemas/confidence-schema.d.ts +36 -0
  19. package/dist/_vendor/ailf-core/schemas/confidence-schema.js +32 -0
  20. package/dist/_vendor/ailf-core/schemas/eval-config.d.ts +1 -0
  21. package/dist/_vendor/ailf-core/schemas/eval-config.js +8 -4
  22. package/dist/_vendor/ailf-core/schemas/index.d.ts +2 -0
  23. package/dist/_vendor/ailf-core/schemas/index.js +9 -0
  24. package/dist/_vendor/ailf-core/schemas/pipeline-request.d.ts +1 -0
  25. package/dist/_vendor/ailf-core/schemas/pipeline-request.js +1 -0
  26. package/dist/_vendor/ailf-core/schemas/pipeline.d.ts +34 -8
  27. package/dist/_vendor/ailf-core/schemas/pipeline.js +23 -1
  28. package/dist/_vendor/ailf-core/services/diagnosis/registry.d.ts +40 -0
  29. package/dist/_vendor/ailf-core/services/diagnosis/registry.js +25 -0
  30. package/dist/_vendor/ailf-core/services/diagnosis-runner.d.ts +19 -0
  31. package/dist/_vendor/ailf-core/services/diagnosis-runner.js +19 -0
  32. package/dist/_vendor/ailf-core/services/index.d.ts +2 -0
  33. package/dist/_vendor/ailf-core/services/index.js +5 -0
  34. package/dist/_vendor/ailf-core/services/report-to-markdown.js +3 -2
  35. package/dist/_vendor/ailf-core/types/attribution.d.ts +82 -0
  36. package/dist/_vendor/ailf-core/types/attribution.js +18 -0
  37. package/dist/_vendor/ailf-core/types/branded-ids.d.ts +26 -1
  38. package/dist/_vendor/ailf-core/types/branded-ids.js +80 -4
  39. package/dist/_vendor/ailf-core/types/confidence.d.ts +68 -0
  40. package/dist/_vendor/ailf-core/types/confidence.js +56 -0
  41. package/dist/_vendor/ailf-core/types/diagnosis.d.ts +169 -0
  42. package/dist/_vendor/ailf-core/types/diagnosis.js +17 -0
  43. package/dist/_vendor/ailf-core/types/generalized-task.d.ts +16 -1
  44. package/dist/_vendor/ailf-core/types/grader-judgment.d.ts +125 -0
  45. package/dist/_vendor/ailf-core/types/grader-judgment.js +30 -0
  46. package/dist/_vendor/ailf-core/types/index.d.ts +82 -29
  47. package/dist/_vendor/ailf-core/types/index.js +16 -1
  48. package/dist/_vendor/ailf-core/types/legacy-grader-judgment.d.ts +55 -0
  49. package/dist/_vendor/ailf-core/types/legacy-grader-judgment.js +30 -0
  50. package/dist/_vendor/ailf-core/types/pipeline-request.d.ts +1 -0
  51. package/dist/_vendor/ailf-core/types/repo-config.d.ts +8 -0
  52. package/dist/_vendor/ailf-shared/document-ref.d.ts +1 -1
  53. package/dist/adapters/api-client/build-request.d.ts +1 -0
  54. package/dist/adapters/api-client/build-request.js +3 -0
  55. package/dist/adapters/attribution/attribution-meta-writer.d.ts +35 -0
  56. package/dist/adapters/attribution/attribution-meta-writer.js +34 -0
  57. package/dist/adapters/attribution/index.d.ts +9 -0
  58. package/dist/adapters/attribution/index.js +8 -0
  59. package/dist/adapters/attribution/per-entry-attribution-writer.d.ts +56 -0
  60. package/dist/adapters/attribution/per-entry-attribution-writer.js +49 -0
  61. package/dist/adapters/config-sources/file-config-adapter.js +1 -0
  62. package/dist/adapters/grader-outputs/index.d.ts +10 -0
  63. package/dist/adapters/grader-outputs/index.js +8 -0
  64. package/dist/adapters/grader-outputs/legacy/index.d.ts +11 -0
  65. package/dist/adapters/grader-outputs/legacy/index.js +10 -0
  66. package/dist/adapters/grader-outputs/legacy/promptfoo-grader-output-legacy.d.ts +49 -0
  67. package/dist/adapters/grader-outputs/legacy/promptfoo-grader-output-legacy.js +48 -0
  68. package/dist/adapters/grader-outputs/promptfoo-grader-output.d.ts +102 -0
  69. package/dist/adapters/grader-outputs/promptfoo-grader-output.js +93 -0
  70. package/dist/adapters/index.d.ts +3 -0
  71. package/dist/adapters/index.js +4 -0
  72. package/dist/adapters/llm/anthropic-llm-client.d.ts +48 -0
  73. package/dist/adapters/llm/anthropic-llm-client.js +205 -0
  74. package/dist/adapters/llm/fake-llm-client.d.ts +49 -0
  75. package/dist/adapters/llm/fake-llm-client.js +63 -0
  76. package/dist/adapters/llm/index.d.ts +9 -0
  77. package/dist/adapters/llm/index.js +4 -0
  78. package/dist/adapters/llm/openai-llm-client.d.ts +44 -0
  79. package/dist/adapters/llm/openai-llm-client.js +168 -0
  80. package/dist/adapters/llm/pricing.d.ts +12 -0
  81. package/dist/adapters/llm/pricing.js +8 -0
  82. package/dist/adapters/llm/retry.d.ts +56 -0
  83. package/dist/adapters/llm/retry.js +66 -0
  84. package/dist/adapters/task-sources/content-lake-task-source.d.ts +5 -1
  85. package/dist/adapters/task-sources/content-lake-task-source.js +28 -2
  86. package/dist/adapters/task-sources/repo-schemas.d.ts +90 -22
  87. package/dist/adapters/task-sources/repo-schemas.js +19 -2
  88. package/dist/artifact-capture/api-gateway-artifact-writer.js +2 -1
  89. package/dist/artifact-capture/batching-api-gateway-artifact-writer.js +2 -1
  90. package/dist/artifact-capture/gcs-artifact-writer.js +3 -1
  91. package/dist/artifact-capture/local-fs-artifact-writer.js +3 -1
  92. package/dist/commands/calculate-scores.js +1 -1
  93. package/dist/commands/explain-handler.js +1 -1
  94. package/dist/commands/lookup-doc.d.ts +1 -1
  95. package/dist/commands/lookup-doc.js +3 -3
  96. package/dist/commands/pipeline-action.d.ts +6 -0
  97. package/dist/commands/pipeline-action.js +2 -0
  98. package/dist/commands/remote-pipeline.js +1 -0
  99. package/dist/composition-root.d.ts +59 -1
  100. package/dist/composition-root.js +95 -0
  101. package/dist/config/rubrics.ts +38 -2
  102. package/dist/grader/agent-harness.d.ts +14 -0
  103. package/dist/grader/agent-harness.js +17 -0
  104. package/dist/grader/common.d.ts +17 -0
  105. package/dist/grader/common.js +21 -0
  106. package/dist/grader/index.d.ts +38 -0
  107. package/dist/grader/index.js +75 -0
  108. package/dist/grader/knowledge-probe.d.ts +14 -0
  109. package/dist/grader/knowledge-probe.js +18 -0
  110. package/dist/grader/literacy.d.ts +13 -0
  111. package/dist/grader/literacy.js +17 -0
  112. package/dist/grader/mcp.d.ts +14 -0
  113. package/dist/grader/mcp.js +18 -0
  114. package/dist/orchestration/build-app-context.js +1 -0
  115. package/dist/orchestration/build-step-sequence.js +5 -0
  116. package/dist/orchestration/steps/calculate-scores-step.js +23 -1
  117. package/dist/orchestration/steps/compute-attribution-step.d.ts +44 -0
  118. package/dist/orchestration/steps/compute-attribution-step.js +279 -0
  119. package/dist/orchestration/steps/gap-analysis-step.js +35 -7
  120. package/dist/orchestration/steps/index.d.ts +1 -0
  121. package/dist/orchestration/steps/index.js +1 -0
  122. package/dist/pipeline/attribution.d.ts +15 -0
  123. package/dist/pipeline/attribution.js +18 -9
  124. package/dist/pipeline/borderline-consensus-runner.d.ts +63 -0
  125. package/dist/pipeline/borderline-consensus-runner.js +124 -0
  126. package/dist/pipeline/borderline-detector.d.ts +24 -0
  127. package/dist/pipeline/borderline-detector.js +26 -0
  128. package/dist/pipeline/calculate-scores.d.ts +114 -3
  129. package/dist/pipeline/calculate-scores.js +426 -24
  130. package/dist/pipeline/compiler/literacy-bridge.d.ts +1 -1
  131. package/dist/pipeline/compiler/literacy-bridge.js +35 -17
  132. package/dist/pipeline/compiler/rubric-resolution.d.ts +15 -0
  133. package/dist/pipeline/compiler/rubric-resolution.js +9 -1
  134. package/dist/pipeline/compute-attribution.d.ts +80 -0
  135. package/dist/pipeline/compute-attribution.js +196 -0
  136. package/dist/pipeline/failure-modes.d.ts +52 -17
  137. package/dist/pipeline/failure-modes.js +178 -117
  138. package/dist/pipeline/map-request-to-config.js +1 -0
  139. package/package.json +6 -4
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Port: LLM access for non-grader features.
3
+ *
4
+ * Adapters wrap a vendor REST API and centralize retry, rate-limit handling,
5
+ * cost calculation, and observability. Features call this port instead of
6
+ * importing the grader's internals or a vendor SDK directly.
7
+ *
8
+ * The grader path (`packages/eval/src/pipeline/grader-api.ts`) is intentionally
9
+ * NOT migrated here — D0051 defers grader migration as a follow-up.
10
+ *
11
+ * @see docs/decisions/D0051-llm-client-port.md
12
+ */
13
+ import type { ZodType } from "zod";
14
+ import { type Brand, type IdValidationError, type Result } from "../types/branded-ids.js";
15
+ /**
16
+ * A canonical LLM model identifier.
17
+ *
18
+ * Grammar: `<provider>:<segment>...:<modelName>` (e.g.
19
+ * `"openai:chat:gpt-5.2"`, `"anthropic:messages:claude-opus-4-6"`,
20
+ * `"anthropic:claude-sonnet-4-6"`). Branded so adapters can trust the
21
+ * grammar and consumers can't accidentally pass an arbitrary string.
22
+ */
23
+ export type ModelId = Brand<string, "ModelId">;
24
+ /** The supported provider prefixes for `ModelId`. */
25
+ export type ModelProvider = "anthropic" | "openai";
26
+ /** Result of parsing a `ModelId` — provider plus the bare model name. */
27
+ export interface ParsedModelId {
28
+ readonly id: ModelId;
29
+ readonly provider: ModelProvider;
30
+ /** Bare vendor model name with provider segments stripped. */
31
+ readonly modelName: string;
32
+ }
33
+ /**
34
+ * Parse a raw string into a `ParsedModelId`. Returns `Result` — never throws.
35
+ *
36
+ * Recognized prefixes:
37
+ * - `openai:<modelName>` or `openai:<sub>:<modelName>` (e.g. `"openai:chat:gpt-5"`)
38
+ * - `anthropic:<modelName>` or `anthropic:messages:<modelName>`
39
+ */
40
+ export declare function parseModelId(raw: string): Result<ParsedModelId, IdValidationError>;
41
+ /**
42
+ * Throwing constructor — convenient for known-good inputs (config files,
43
+ * tests). Throws if the id is malformed; use `parseModelId` for untrusted
44
+ * input.
45
+ */
46
+ export declare function modelId(raw: string): ModelId;
47
+ /**
48
+ * Extract `provider` + `modelName` from an already-branded `ModelId`. Assumes
49
+ * the id was produced by `parseModelId` / `modelId` and is therefore valid;
50
+ * if it isn't, the caller's bug surfaces as a thrown `Error`.
51
+ */
52
+ export declare function splitModelId(id: ModelId): ParsedModelId;
53
+ /**
54
+ * Per-call telemetry tag. Carried through usage / cost records so billing can
55
+ * roll up by feature, run, or card.
56
+ */
57
+ export interface LLMCallContext {
58
+ /** Logical feature name (e.g. "diagnosis", "meta-eval"). */
59
+ feature: string;
60
+ /** Optional pipeline run id when the call happens inside a run. */
61
+ runId?: string;
62
+ /** Optional originating card id (for diagnosis-style features). */
63
+ cardId?: string;
64
+ }
65
+ /** Token usage reported by the vendor for a single call. */
66
+ export interface LLMUsage {
67
+ promptTokens: number;
68
+ completionTokens: number;
69
+ }
70
+ /** Result of a free-text completion. */
71
+ export interface LLMCompletion {
72
+ text: string;
73
+ usage: LLMUsage;
74
+ /** End-to-end USD cost for the call. */
75
+ cost: number;
76
+ /** Echo of the canonical model id used. */
77
+ model: ModelId;
78
+ }
79
+ /** Result of a structured-output completion. `value` is parsed via the supplied schema. */
80
+ export interface LLMStructuredCompletion<T> {
81
+ value: T;
82
+ usage: LLMUsage;
83
+ cost: number;
84
+ model: ModelId;
85
+ }
86
+ export interface LLMCompleteArgs {
87
+ /** Canonical model id — produced by `modelId` / `parseModelId`. */
88
+ model: ModelId;
89
+ /** Raw prompt text — adapters wrap it in the vendor message envelope. */
90
+ prompt: string;
91
+ temperature?: number;
92
+ maxTokens?: number;
93
+ stop?: string[];
94
+ context?: LLMCallContext;
95
+ }
96
+ export interface LLMCompleteStructuredArgs<T> {
97
+ model: ModelId;
98
+ prompt: string;
99
+ /** Runtime contract — the adapter parses the model's response through this. */
100
+ schema: ZodType<T>;
101
+ temperature?: number;
102
+ maxTokens?: number;
103
+ context?: LLMCallContext;
104
+ }
105
+ /**
106
+ * Synthesis-side LLM port. v0 is single-call only — streaming and batching are
107
+ * deferred per D0051 until a consumer needs them.
108
+ */
109
+ export interface LLMClient {
110
+ complete(args: LLMCompleteArgs): Promise<LLMCompletion>;
111
+ completeStructured<T>(args: LLMCompleteStructuredArgs<T>): Promise<LLMStructuredCompletion<T>>;
112
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Port: LLM access for non-grader features.
3
+ *
4
+ * Adapters wrap a vendor REST API and centralize retry, rate-limit handling,
5
+ * cost calculation, and observability. Features call this port instead of
6
+ * importing the grader's internals or a vendor SDK directly.
7
+ *
8
+ * The grader path (`packages/eval/src/pipeline/grader-api.ts`) is intentionally
9
+ * NOT migrated here — D0051 defers grader migration as a follow-up.
10
+ *
11
+ * @see docs/decisions/D0051-llm-client-port.md
12
+ */
13
+ import { err, ok, } from "../types/branded-ids.js";
14
+ /**
15
+ * Parse a raw string into a `ParsedModelId`. Returns `Result` — never throws.
16
+ *
17
+ * Recognized prefixes:
18
+ * - `openai:<modelName>` or `openai:<sub>:<modelName>` (e.g. `"openai:chat:gpt-5"`)
19
+ * - `anthropic:<modelName>` or `anthropic:messages:<modelName>`
20
+ */
21
+ export function parseModelId(raw) {
22
+ const parts = raw.split(":");
23
+ if (parts.length < 2 || parts[0] === "" || parts.some((p) => p === "")) {
24
+ return err({
25
+ code: "INVALID_MODEL_ID",
26
+ raw,
27
+ message: `Invalid ModelId "${raw}": expected "<provider>:<modelName>" with non-empty segments`,
28
+ });
29
+ }
30
+ const provider = parts[0];
31
+ if (provider === "openai") {
32
+ const modelName = parts.length >= 3 ? parts.slice(2).join(":") : parts.slice(1).join(":");
33
+ return ok({ id: raw, provider, modelName });
34
+ }
35
+ if (provider === "anthropic") {
36
+ const modelName = parts.length >= 3 && parts[1] === "messages"
37
+ ? parts.slice(2).join(":")
38
+ : parts.slice(1).join(":");
39
+ return ok({ id: raw, provider, modelName });
40
+ }
41
+ return err({
42
+ code: "INVALID_MODEL_ID",
43
+ raw,
44
+ message: `Invalid ModelId "${raw}": unknown provider "${provider}". Supported: openai, anthropic.`,
45
+ });
46
+ }
47
+ /**
48
+ * Throwing constructor — convenient for known-good inputs (config files,
49
+ * tests). Throws if the id is malformed; use `parseModelId` for untrusted
50
+ * input.
51
+ */
52
+ export function modelId(raw) {
53
+ const result = parseModelId(raw);
54
+ if (!result.ok)
55
+ throw new Error(result.error.message);
56
+ return result.value.id;
57
+ }
58
+ /**
59
+ * Extract `provider` + `modelName` from an already-branded `ModelId`. Assumes
60
+ * the id was produced by `parseModelId` / `modelId` and is therefore valid;
61
+ * if it isn't, the caller's bug surfaces as a thrown `Error`.
62
+ */
63
+ export function splitModelId(id) {
64
+ const result = parseModelId(id);
65
+ if (!result.ok)
66
+ throw new Error(result.error.message);
67
+ return result.value;
68
+ }
@@ -81,7 +81,22 @@ export interface ModeRubricConfig {
81
81
  header: string;
82
82
  scale: string[];
83
83
  criteria_label?: string;
84
+ /**
85
+ * Plan 03-02 — per-dimension legal failure-mode list. The runtime
86
+ * rubric assembler announces these modes to the grader before the
87
+ * structured-shape footer when the list is non-empty. Stamped at
88
+ * config-load time by `failureModesForDimension(dimension)` in
89
+ * `packages/eval/src/grader/index.ts`.
90
+ */
91
+ failureModes?: readonly string[];
84
92
  }>;
93
+ /**
94
+ * Plan 03-01 — formerly hard-coded literal in
95
+ * `pipeline/compiler/rubric-resolution.ts`; now sourced from
96
+ * RubricConfig.footer and threaded through to the runtime prompt
97
+ * assembler so the grader is told exactly what wire format to emit.
98
+ */
99
+ footer: string;
85
100
  }
86
101
  /** A provider entry in the compile result */
87
102
  export interface CompileResultProvider {
@@ -0,0 +1,40 @@
1
+ /**
2
+ * branded-string.ts — single, audited cast site for Zod schemas that
3
+ * parse a non-empty string into a {@link Brand}-tagged domain type.
4
+ *
5
+ * Project rule (`.claude/rules/typescript.md`): "Parse, don't validate
6
+ * — use schema libs at boundaries; no `as` on `unknown`." The
7
+ * `Brand<string, "Tag">` utility in `branded-ids.ts` uses a `unique
8
+ * symbol` (`__brand`) that is not structurally identical to Zod 4's
9
+ * `BRAND` symbol, so a direct `.brand<"Tag">()` swap does not produce
10
+ * a compatible type. Wrapping the unavoidable cast in a single typed
11
+ * helper centralizes the rule violation to one auditable place
12
+ * instead of duplicating `as unknown as z.ZodType<Brand<…, …>>` at
13
+ * every adapter branded-field declaration.
14
+ *
15
+ * Usage:
16
+ *
17
+ * ```ts
18
+ * import { brandedString } from "../schemas/index.d.ts"
19
+ *
20
+ * judgmentId: brandedString<"JudgmentId">().optional(),
21
+ * ```
22
+ *
23
+ * This is the **only** allowed place to elide the no-`as`-on-`unknown`
24
+ * rule for branded-string schemas. Phase 7 will reconsider the
25
+ * `Brand<>` shape against Zod 4's `BRAND` so the cast can be retired.
26
+ *
27
+ * @see docs/decisions/D0045-type-architecture-and-contract-enforcement.md
28
+ * @see packages/core/src/types/branded-ids.ts
29
+ */
30
+ import { z } from "zod";
31
+ import type { Brand } from "../types/branded-ids.js";
32
+ /**
33
+ * Schema for a non-empty string typed as `Brand<string, TBrand>`.
34
+ *
35
+ * The single `as unknown as` cast inside this helper is the audited
36
+ * exit from the project's no-`as`-on-`unknown` rule. Adapters MUST
37
+ * NOT replicate the cast at their own call sites — call this helper
38
+ * instead so the rule violation stays centralized.
39
+ */
40
+ export declare function brandedString<TBrand extends string>(): z.ZodType<Brand<string, TBrand>>;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * branded-string.ts — single, audited cast site for Zod schemas that
3
+ * parse a non-empty string into a {@link Brand}-tagged domain type.
4
+ *
5
+ * Project rule (`.claude/rules/typescript.md`): "Parse, don't validate
6
+ * — use schema libs at boundaries; no `as` on `unknown`." The
7
+ * `Brand<string, "Tag">` utility in `branded-ids.ts` uses a `unique
8
+ * symbol` (`__brand`) that is not structurally identical to Zod 4's
9
+ * `BRAND` symbol, so a direct `.brand<"Tag">()` swap does not produce
10
+ * a compatible type. Wrapping the unavoidable cast in a single typed
11
+ * helper centralizes the rule violation to one auditable place
12
+ * instead of duplicating `as unknown as z.ZodType<Brand<…, …>>` at
13
+ * every adapter branded-field declaration.
14
+ *
15
+ * Usage:
16
+ *
17
+ * ```ts
18
+ * import { brandedString } from "../schemas/index.js"
19
+ *
20
+ * judgmentId: brandedString<"JudgmentId">().optional(),
21
+ * ```
22
+ *
23
+ * This is the **only** allowed place to elide the no-`as`-on-`unknown`
24
+ * rule for branded-string schemas. Phase 7 will reconsider the
25
+ * `Brand<>` shape against Zod 4's `BRAND` so the cast can be retired.
26
+ *
27
+ * @see docs/decisions/D0045-type-architecture-and-contract-enforcement.md
28
+ * @see packages/core/src/types/branded-ids.ts
29
+ */
30
+ import { z } from "zod";
31
+ /**
32
+ * Schema for a non-empty string typed as `Brand<string, TBrand>`.
33
+ *
34
+ * The single `as unknown as` cast inside this helper is the audited
35
+ * exit from the project's no-`as`-on-`unknown` rule. Adapters MUST
36
+ * NOT replicate the cast at their own call sites — call this helper
37
+ * instead so the rule violation stays centralized.
38
+ */
39
+ export function brandedString() {
40
+ // The runtime is a plain non-empty string; the brand is a
41
+ // compile-time-only nominal tag (see `Brand<>` in branded-ids.ts).
42
+ // Zod 4's `.brand()` uses a different symbol shape, so a direct
43
+ // composition does not yield the project's `Brand<…>` type.
44
+ return z.string().min(1);
45
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * confidence-schema.ts — shared Zod schema for the D0049 `Confidence` triple.
3
+ *
4
+ * Authored ONCE here so adapter schemas under
5
+ * `packages/eval/src/adapters/grader-outputs/` and
6
+ * `packages/eval/src/adapters/attribution/` import a single shared schema
7
+ * fragment instead of redeclaring the shape inline. The schema asserts
8
+ * `satisfies z.ZodType<Confidence>` against the domain type in
9
+ * `packages/core/src/types/confidence.ts` so drift is a build error.
10
+ *
11
+ * NON-BOUNDARY HELPER: this file lives outside the D0045 SCAN_ROOTS gate
12
+ * by intent — it is a reusable schema fragment, not a trust boundary.
13
+ * Consumers import via the pinned subpath export
14
+ * `@sanity/ailf-core/schemas` (declared in `packages/core/package.json`),
15
+ * NOT through the top-level barrel — that pin is the
16
+ * single legal access path so all adapter sites use the same specifier.
17
+ *
18
+ * @see docs/decisions/D0045-type-architecture-and-contract-enforcement.md
19
+ * @see docs/decisions/D0049-shared-confidence-contract.md
20
+ */
21
+ import { z } from "zod";
22
+ /**
23
+ * Shared schema for {@link Confidence}. The `derivation` field is the
24
+ * open `ConfidenceDerivation` tag; we accept any non-empty string so
25
+ * future emitters can mint their own identifiers without editing this
26
+ * package (matches `isConfidence`'s runtime guard).
27
+ */
28
+ export declare const ConfidenceSchema: z.ZodObject<{
29
+ level: z.ZodEnum<{
30
+ low: "low";
31
+ medium: "medium";
32
+ high: "high";
33
+ }>;
34
+ signalsPresent: z.ZodNumber;
35
+ derivation: z.ZodString;
36
+ }, z.core.$strip>;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * confidence-schema.ts — shared Zod schema for the D0049 `Confidence` triple.
3
+ *
4
+ * Authored ONCE here so adapter schemas under
5
+ * `packages/eval/src/adapters/grader-outputs/` and
6
+ * `packages/eval/src/adapters/attribution/` import a single shared schema
7
+ * fragment instead of redeclaring the shape inline. The schema asserts
8
+ * `satisfies z.ZodType<Confidence>` against the domain type in
9
+ * `packages/core/src/types/confidence.ts` so drift is a build error.
10
+ *
11
+ * NON-BOUNDARY HELPER: this file lives outside the D0045 SCAN_ROOTS gate
12
+ * by intent — it is a reusable schema fragment, not a trust boundary.
13
+ * Consumers import via the pinned subpath export
14
+ * `@sanity/ailf-core/schemas` (declared in `packages/core/package.json`),
15
+ * NOT through the top-level barrel — that pin is the
16
+ * single legal access path so all adapter sites use the same specifier.
17
+ *
18
+ * @see docs/decisions/D0045-type-architecture-and-contract-enforcement.md
19
+ * @see docs/decisions/D0049-shared-confidence-contract.md
20
+ */
21
+ import { z } from "zod";
22
+ /**
23
+ * Shared schema for {@link Confidence}. The `derivation` field is the
24
+ * open `ConfidenceDerivation` tag; we accept any non-empty string so
25
+ * future emitters can mint their own identifiers without editing this
26
+ * package (matches `isConfidence`'s runtime guard).
27
+ */
28
+ export const ConfidenceSchema = z.object({
29
+ level: z.enum(["high", "medium", "low"]),
30
+ signalsPresent: z.number().int().nonnegative(),
31
+ derivation: z.string().min(1),
32
+ });
@@ -41,6 +41,7 @@ export declare const EvalConfigSchema: z.ZodObject<{
41
41
  execution: z.ZodOptional<z.ZodObject<{
42
42
  concurrency: z.ZodOptional<z.ZodNumber>;
43
43
  graderReplications: z.ZodOptional<z.ZodNumber>;
44
+ borderlineReplications: z.ZodOptional<z.ZodNumber>;
44
45
  gapAnalysis: z.ZodOptional<z.ZodBoolean>;
45
46
  apiUrl: z.ZodOptional<z.ZodString>;
46
47
  }, z.core.$strip>>;
@@ -85,15 +85,19 @@ export const EvalConfigSchema = z
85
85
  * `concurrency`, `gapAnalysis`, and `graderReplications` fields and adds
86
86
  * `apiUrl` to the same group.
87
87
  *
88
- * - `concurrency` — max parallel API calls
89
- * - `graderReplications` — grader consistency replications
90
- * - `gapAnalysis` enable failure-mode + impact analysis (default true)
91
- * - `apiUrl` — AILF API base URL (default https://ailf-api.sanity.build)
88
+ * - `concurrency` — max parallel API calls
89
+ * - `graderReplications` — grader consistency replications
90
+ * - `borderlineReplications` replications per borderline judgment
91
+ * for the GRAD-04 intra-grader consensus
92
+ * pass (default 3 in composition-root)
93
+ * - `gapAnalysis` — enable failure-mode + impact analysis (default true)
94
+ * - `apiUrl` — AILF API base URL (default https://ailf-api.sanity.build)
92
95
  */
93
96
  execution: z
94
97
  .object({
95
98
  concurrency: z.number().int().positive().optional(),
96
99
  graderReplications: z.number().int().positive().optional(),
100
+ borderlineReplications: z.number().int().positive().optional(),
97
101
  gapAnalysis: z.boolean().optional(),
98
102
  apiUrl: z.string().url().optional(),
99
103
  })
@@ -19,3 +19,5 @@ export * from "./schedules.js";
19
19
  export * from "./sinks.js";
20
20
  export * from "./symbol-preflight-report.js";
21
21
  export * from "./test-budgets.js";
22
+ export { ConfidenceSchema } from "./confidence-schema.js";
23
+ export { brandedString } from "./branded-string.js";
@@ -19,3 +19,12 @@ export * from "./schedules.js";
19
19
  export * from "./sinks.js";
20
20
  export * from "./symbol-preflight-report.js";
21
21
  export * from "./test-budgets.js";
22
+ // Phase 1 Plan 02 — shared schema fragment for D0049 Confidence.
23
+ // Named re-export only (W0124 / D0045) and pinned-subpath access path
24
+ // `@sanity/ailf-core/schemas` for adapter consumers.
25
+ export { ConfidenceSchema } from "./confidence-schema.js";
26
+ // Phase 1 Plan 03 — single audited cast site for `Brand<string, T>`
27
+ // schemas. Adapters MUST route branded-field declarations through this
28
+ // helper instead of replicating `as unknown as z.ZodType<…>` at each
29
+ // schema author site (project rule: no `as` on `unknown`).
30
+ export { brandedString } from "./branded-string.js";
@@ -48,6 +48,7 @@ export declare const PipelineRequestSchema: z.ZodObject<{
48
48
  "with-docs": "with-docs";
49
49
  }>>;
50
50
  graderReplications: z.ZodOptional<z.ZodNumber>;
51
+ borderlineReplications: z.ZodOptional<z.ZodNumber>;
51
52
  headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
52
53
  inlineTasks: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
53
54
  jobId: z.ZodOptional<z.ZodString>;
@@ -114,6 +114,7 @@ export const PipelineRequestSchema = z.object({
114
114
  */
115
115
  graderContext: z.enum(["rubric-only", "with-docs"]).optional(),
116
116
  graderReplications: z.number().int().positive().optional(),
117
+ borderlineReplications: z.number().int().positive().optional(),
117
118
  headers: z.record(z.string(), z.string()).optional(),
118
119
  inlineTasks: z.array(z.record(z.string(), z.unknown())).optional(),
119
120
  jobId: z.string().optional(),
@@ -20,6 +20,7 @@ import { z } from "zod";
20
20
  export declare const RubricTemplateSchema: z.ZodObject<{
21
21
  criteria_label: z.ZodOptional<z.ZodNullable<z.ZodString>>;
22
22
  dimension: z.ZodOptional<z.ZodString>;
23
+ failureModes: z.ZodOptional<z.ZodArray<z.ZodString>>;
23
24
  header: z.ZodString;
24
25
  scale: z.ZodArray<z.ZodString>;
25
26
  }, z.core.$strip>;
@@ -52,6 +53,7 @@ export declare const RubricConfigSchema: z.ZodObject<{
52
53
  templates: z.ZodRecord<z.ZodString, z.ZodObject<{
53
54
  criteria_label: z.ZodOptional<z.ZodNullable<z.ZodString>>;
54
55
  dimension: z.ZodOptional<z.ZodString>;
56
+ failureModes: z.ZodOptional<z.ZodArray<z.ZodString>>;
55
57
  header: z.ZodString;
56
58
  scale: z.ZodArray<z.ZodString>;
57
59
  }, z.core.$strip>>;
@@ -112,7 +114,10 @@ export type FeatureRegistry = z.infer<typeof FeatureRegistrySchema>;
112
114
  * and provides task-specific criteria.
113
115
  */
114
116
  declare const TemplatedLlmRubricAssertSchema: z.ZodObject<{
115
- criteria: z.ZodArray<z.ZodString>;
117
+ criteria: z.ZodArray<z.ZodObject<{
118
+ id: z.ZodString;
119
+ text: z.ZodString;
120
+ }, z.core.$strip>>;
116
121
  template: z.ZodString;
117
122
  type: z.ZodLiteral<"llm-rubric">;
118
123
  weight: z.ZodOptional<z.ZodNumber>;
@@ -129,7 +134,10 @@ export type TemplatedLlmRubricAssert = z.infer<typeof TemplatedLlmRubricAssertSc
129
134
  * is gone, but union is more flexible for future additions).
130
135
  */
131
136
  export declare const AssertionSchema: z.ZodUnion<readonly [z.ZodObject<{
132
- criteria: z.ZodArray<z.ZodString>;
137
+ criteria: z.ZodArray<z.ZodObject<{
138
+ id: z.ZodString;
139
+ text: z.ZodString;
140
+ }, z.core.$strip>>;
133
141
  template: z.ZodString;
134
142
  type: z.ZodLiteral<"llm-rubric">;
135
143
  weight: z.ZodOptional<z.ZodNumber>;
@@ -174,7 +182,10 @@ export type CanonicalDoc = z.infer<typeof CanonicalDocSchema>;
174
182
  */
175
183
  export declare const SingleTaskSchema: z.ZodObject<{
176
184
  assert: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
177
- criteria: z.ZodArray<z.ZodString>;
185
+ criteria: z.ZodArray<z.ZodObject<{
186
+ id: z.ZodString;
187
+ text: z.ZodString;
188
+ }, z.core.$strip>>;
178
189
  template: z.ZodString;
179
190
  type: z.ZodLiteral<"llm-rubric">;
180
191
  weight: z.ZodOptional<z.ZodNumber>;
@@ -233,7 +244,10 @@ export type SingleTask = z.infer<typeof SingleTaskSchema>;
233
244
  */
234
245
  export declare const LegacyTaskSchema: z.ZodObject<{
235
246
  assert: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
236
- criteria: z.ZodArray<z.ZodString>;
247
+ criteria: z.ZodArray<z.ZodObject<{
248
+ id: z.ZodString;
249
+ text: z.ZodString;
250
+ }, z.core.$strip>>;
237
251
  template: z.ZodString;
238
252
  type: z.ZodLiteral<"llm-rubric">;
239
253
  weight: z.ZodOptional<z.ZodNumber>;
@@ -269,7 +283,10 @@ export type LegacyTask = z.infer<typeof LegacyTaskSchema>;
269
283
  */
270
284
  export declare const TaskEntrySchema: z.ZodUnion<readonly [z.ZodObject<{
271
285
  assert: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
272
- criteria: z.ZodArray<z.ZodString>;
286
+ criteria: z.ZodArray<z.ZodObject<{
287
+ id: z.ZodString;
288
+ text: z.ZodString;
289
+ }, z.core.$strip>>;
273
290
  template: z.ZodString;
274
291
  type: z.ZodLiteral<"llm-rubric">;
275
292
  weight: z.ZodOptional<z.ZodNumber>;
@@ -321,7 +338,10 @@ export declare const TaskEntrySchema: z.ZodUnion<readonly [z.ZodObject<{
321
338
  }, z.core.$loose>;
322
339
  }, z.core.$strip>, z.ZodObject<{
323
340
  assert: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
324
- criteria: z.ZodArray<z.ZodString>;
341
+ criteria: z.ZodArray<z.ZodObject<{
342
+ id: z.ZodString;
343
+ text: z.ZodString;
344
+ }, z.core.$strip>>;
325
345
  template: z.ZodString;
326
346
  type: z.ZodLiteral<"llm-rubric">;
327
347
  weight: z.ZodOptional<z.ZodNumber>;
@@ -355,7 +375,10 @@ export type TaskEntryParsed = z.infer<typeof TaskEntrySchema>;
355
375
  */
356
376
  export declare const TaskFileSchema: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
357
377
  assert: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
358
- criteria: z.ZodArray<z.ZodString>;
378
+ criteria: z.ZodArray<z.ZodObject<{
379
+ id: z.ZodString;
380
+ text: z.ZodString;
381
+ }, z.core.$strip>>;
359
382
  template: z.ZodString;
360
383
  type: z.ZodLiteral<"llm-rubric">;
361
384
  weight: z.ZodOptional<z.ZodNumber>;
@@ -407,7 +430,10 @@ export declare const TaskFileSchema: z.ZodArray<z.ZodUnion<readonly [z.ZodObject
407
430
  }, z.core.$loose>;
408
431
  }, z.core.$strip>, z.ZodObject<{
409
432
  assert: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
410
- criteria: z.ZodArray<z.ZodString>;
433
+ criteria: z.ZodArray<z.ZodObject<{
434
+ id: z.ZodString;
435
+ text: z.ZodString;
436
+ }, z.core.$strip>>;
411
437
  template: z.ZodString;
412
438
  type: z.ZodLiteral<"llm-rubric">;
413
439
  weight: z.ZodOptional<z.ZodNumber>;
@@ -26,6 +26,14 @@ export const RubricTemplateSchema = z.object({
26
26
  .min(1, "criteria_label must be a non-empty string")
27
27
  .nullish(),
28
28
  dimension: z.string().min(1).optional(),
29
+ /**
30
+ * Plan 03-02 — per-dimension legal failure-mode list. When present and
31
+ * non-empty, the runtime rubric assembler announces the legal modes to
32
+ * the grader before the structured-shape footer (Plan 03-01).
33
+ * Stamped at config-load time by `failureModesForDimension(dimension)`
34
+ * from `packages/eval/src/grader/index.ts`.
35
+ */
36
+ failureModes: z.array(z.string().min(1)).optional(),
29
37
  header: z.string().min(1, "header must be a non-empty string"),
30
38
  scale: z
31
39
  .array(z.string().min(1))
@@ -118,13 +126,27 @@ export const FeatureRegistrySchema = z.object({
118
126
  // ---------------------------------------------------------------------------
119
127
  // Assertion schemas — one per Promptfoo assertion type
120
128
  // ---------------------------------------------------------------------------
129
+ // TODO(GRAD-01 follow-up): This schema duplicates
130
+ // packages/eval/src/adapters/task-sources/repo-schemas.ts:TemplatedAssertionSchema.
131
+ // Retiring requires reverse-extracting the canonical schema into
132
+ // packages/core/src/schemas/ (D0048 prevents importing from packages/eval).
133
+ // Out of Phase 2 scope; tracked separately.
134
+ //
135
+ // The `satisfies z.ZodType<CriterionRef>` clause asserts this duplicate
136
+ // stays shape-compatible with the canonical domain type in
137
+ // `@sanity/ailf-core` (D0045). If a future edit adds a third field to one
138
+ // schema and not the other, this build error catches the drift.
139
+ const CriterionRefShape = z.object({
140
+ id: z.string().min(1, "id must be a non-empty slug"),
141
+ text: z.string().min(1, "text must be a non-empty string"),
142
+ });
121
143
  /**
122
144
  * Templated llm-rubric assertion — references a rubric template by key
123
145
  * and provides task-specific criteria.
124
146
  */
125
147
  const TemplatedLlmRubricAssertSchema = z.object({
126
148
  criteria: z
127
- .array(z.string().min(1))
149
+ .array(CriterionRefShape)
128
150
  .min(1, "criteria must have at least one entry"),
129
151
  template: z.string().min(1, "template must be a non-empty string"),
130
152
  type: z.literal("llm-rubric"),
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Diagnosis card registry — placeholder home for Phase 5 cards.
3
+ *
4
+ * Phase 5 cards declare:
5
+ *
6
+ * export const card = {
7
+ * type, version, schema, generate
8
+ * } satisfies CardDefinition
9
+ *
10
+ * The compound `cardVersion` (VER-01 / D-02) is built from per-card
11
+ * `version` by sorting `${type}@${version}` ascending and joining with
12
+ * `,`. Phase 1 lands the empty registry; Phase 5 registers cards via
13
+ * the composition root, not by mutating this binding.
14
+ *
15
+ * @see docs/decisions/D0045-type-architecture-and-contract-enforcement.md
16
+ * @see docs/decisions/D0048-engine-homes-for-cli-api-parity.md
17
+ * @see .planning/phases/01-foundation-contracts-cross-cutting-schemas/01-CONTEXT.md (D-02, D-08)
18
+ */
19
+ import type { z } from "zod";
20
+ import type { CardType, DiagnosisCard } from "../../types/diagnosis.js";
21
+ /**
22
+ * Per-card definition. `schema` is the per-card body parser; `generate`
23
+ * is the runner-invoked builder. Phase 5 fills in the
24
+ * `report+attribution+llm` parameter list when card files land — Phase 1
25
+ * keeps the signature minimal so the registry compiles before any cards
26
+ * exist.
27
+ */
28
+ export interface CardDefinition<TBody = unknown> {
29
+ readonly type: CardType;
30
+ readonly version: string;
31
+ readonly schema: z.ZodType<TBody>;
32
+ readonly generate: () => Promise<DiagnosisCard>;
33
+ }
34
+ /**
35
+ * Phase 1: empty entrypoint. Phase 5 cards register here through the
36
+ * composition root. The exported binding is a `ReadonlyMap` so
37
+ * downstream consumers cannot mutate it (would re-introduce the vitest
38
+ * worker-leak hazard).
39
+ */
40
+ export declare const cardRegistry: ReadonlyMap<CardType, CardDefinition>;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Diagnosis card registry — placeholder home for Phase 5 cards.
3
+ *
4
+ * Phase 5 cards declare:
5
+ *
6
+ * export const card = {
7
+ * type, version, schema, generate
8
+ * } satisfies CardDefinition
9
+ *
10
+ * The compound `cardVersion` (VER-01 / D-02) is built from per-card
11
+ * `version` by sorting `${type}@${version}` ascending and joining with
12
+ * `,`. Phase 1 lands the empty registry; Phase 5 registers cards via
13
+ * the composition root, not by mutating this binding.
14
+ *
15
+ * @see docs/decisions/D0045-type-architecture-and-contract-enforcement.md
16
+ * @see docs/decisions/D0048-engine-homes-for-cli-api-parity.md
17
+ * @see .planning/phases/01-foundation-contracts-cross-cutting-schemas/01-CONTEXT.md (D-02, D-08)
18
+ */
19
+ /**
20
+ * Phase 1: empty entrypoint. Phase 5 cards register here through the
21
+ * composition root. The exported binding is a `ReadonlyMap` so
22
+ * downstream consumers cannot mutate it (would re-introduce the vitest
23
+ * worker-leak hazard).
24
+ */
25
+ export const cardRegistry = new Map();