eval-quality 0.1.0 → 0.3.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 (179) hide show
  1. package/README.md +142 -67
  2. package/corpus/dev/README.md +20 -13
  3. package/corpus/dev/compile-seal-example/brief.json +1 -1
  4. package/corpus/dev/compile-seal-example/contract.json +1 -1
  5. package/corpus/dev/contracts/absent-collection-locations.json +1 -1
  6. package/corpus/dev/contracts/absent-sibling-groups.json +1 -1
  7. package/corpus/dev/contracts/absent-success-indicator.json +1 -1
  8. package/corpus/dev/contracts/empty-channel-roles.json +1 -1
  9. package/corpus/dev/contracts/empty-collection-locations.json +1 -1
  10. package/corpus/dev/contracts/empty-request-shapes.json +1 -1
  11. package/corpus/dev/contracts/empty-sibling-groups.json +1 -1
  12. package/corpus/dev/contracts/fragment-selection.json +1 -0
  13. package/corpus/dev/contracts/no-collection-quantifier.json +1 -1
  14. package/corpus/dev/contracts/no-operation-inventory.json +1 -1
  15. package/corpus/dev/contracts/no-read-back-relation.json +1 -1
  16. package/corpus/dev/contracts/no-state-change-marker.json +1 -1
  17. package/corpus/dev/contracts/no-type-violating-step.json +1 -1
  18. package/corpus/dev/contracts/per-key-split-oracles.json +1 -1
  19. package/corpus/dev/contracts/review-corpus.json +1 -0
  20. package/corpus/dev/contracts/satisfied-declarations.json +1 -1
  21. package/corpus/dev/contracts/single-required-response-key.json +1 -1
  22. package/corpus/dev/contracts/split-indicator-oracle.json +1 -1
  23. package/corpus/dev/contracts/unaddressed-parameter-sibling.json +1 -1
  24. package/corpus/dev/contracts/unnamed-reference-set.json +1 -1
  25. package/corpus/dev/contracts/wrong-cardinality-form.json +1 -1
  26. package/corpus/dev/index.json +1 -1
  27. package/dist/application/index.d.ts +2 -0
  28. package/dist/application/index.js +1 -0
  29. package/dist/application/score.d.ts +48 -0
  30. package/dist/application/score.js +186 -0
  31. package/dist/cli/arguments.d.ts +7 -3
  32. package/dist/cli/arguments.js +73 -5
  33. package/dist/cli/exit-codes.d.ts +6 -2
  34. package/dist/cli/exit-codes.js +8 -9
  35. package/dist/cli/main.js +9 -0
  36. package/dist/cli/render.d.ts +3 -6
  37. package/dist/cli/render.js +57 -5
  38. package/dist/cli/run.d.ts +13 -3
  39. package/dist/cli/run.js +136 -16
  40. package/dist/core/canonical/canonicalize.d.ts +12 -0
  41. package/dist/core/canonical/canonicalize.js +18 -4
  42. package/dist/core/compile/bindings.d.ts +89 -0
  43. package/dist/core/compile/bindings.js +334 -0
  44. package/dist/core/compile/compile.d.ts +17 -0
  45. package/dist/core/compile/compile.js +37 -1
  46. package/dist/core/compile/excluded-content.d.ts +11 -0
  47. package/dist/core/compile/excluded-content.js +42 -0
  48. package/dist/core/compile/expression-legality.d.ts +49 -0
  49. package/dist/core/compile/expression-legality.js +158 -38
  50. package/dist/core/compile/forbidden-inputs.d.ts +8 -1
  51. package/dist/core/compile/forbidden-inputs.js +16 -3
  52. package/dist/core/compile/interface-inventory.d.ts +57 -2
  53. package/dist/core/compile/interface-inventory.js +119 -13
  54. package/dist/core/compile/reachability.d.ts +28 -1
  55. package/dist/core/compile/reachability.js +167 -35
  56. package/dist/core/compile/schema-version.d.ts +2 -0
  57. package/dist/core/compile/schema-version.js +25 -0
  58. package/dist/core/compile/sensitivity-witness.d.ts +31 -12
  59. package/dist/core/compile/sensitivity-witness.js +110 -23
  60. package/dist/core/compile/step-reference.d.ts +2 -0
  61. package/dist/core/compile/step-reference.js +49 -0
  62. package/dist/core/coverage/operations.d.ts +62 -0
  63. package/dist/core/coverage/operations.js +57 -0
  64. package/dist/core/coverage/relevance.d.ts +4 -2
  65. package/dist/core/coverage/relevance.js +22 -23
  66. package/dist/core/coverage/satisfaction.d.ts +2 -2
  67. package/dist/core/coverage/satisfaction.js +73 -48
  68. package/dist/core/declared-inputs.d.ts +83 -4
  69. package/dist/core/declared-inputs.js +105 -8
  70. package/dist/core/emit/emit.d.ts +9 -0
  71. package/dist/core/emit/emit.js +214 -0
  72. package/dist/core/emit/private-artifact-digest.d.ts +11 -0
  73. package/dist/core/emit/private-artifact-digest.js +31 -0
  74. package/dist/core/evaluate/evidence-resolution.d.ts +10 -3
  75. package/dist/core/evaluate/evidence-resolution.js +74 -11
  76. package/dist/core/evaluate/operators.d.ts +22 -0
  77. package/dist/core/evaluate/operators.js +17 -1
  78. package/dist/core/evaluate/resolution.d.ts +14 -3
  79. package/dist/core/evaluate/resolution.js +63 -3
  80. package/dist/core/excluded-content.d.ts +65 -0
  81. package/dist/core/excluded-content.js +113 -0
  82. package/dist/core/failure-codes.d.ts +2 -2
  83. package/dist/core/failure-codes.js +7 -2
  84. package/dist/core/ingest/conditions.d.ts +201 -0
  85. package/dist/core/ingest/conditions.js +48 -0
  86. package/dist/core/ingest/index.d.ts +13 -0
  87. package/dist/core/ingest/index.js +11 -0
  88. package/dist/core/ingest/ingest.d.ts +68 -0
  89. package/dist/core/ingest/ingest.js +318 -0
  90. package/dist/core/lineage/stage-table.d.ts +21 -4
  91. package/dist/core/lineage/stage-table.js +35 -3
  92. package/dist/core/preflight/plan.d.ts +7 -5
  93. package/dist/core/preflight/plan.js +75 -32
  94. package/dist/core/preflight/projection.d.ts +6 -3
  95. package/dist/core/preflight/projection.js +22 -2
  96. package/dist/core/preflight/reduce.js +47 -7
  97. package/dist/core/preflight/witness-evidence.d.ts +5 -5
  98. package/dist/core/preflight/witness-evidence.js +73 -20
  99. package/dist/core/schemas/artifact.d.ts +1049 -30
  100. package/dist/core/schemas/constraint-ledger.js +51 -0
  101. package/dist/core/schemas/defect-signature.d.ts +695 -0
  102. package/dist/core/schemas/defect-signature.js +175 -0
  103. package/dist/core/schemas/eval-contract.d.ts +550 -12
  104. package/dist/core/schemas/eval-contract.js +32 -2
  105. package/dist/core/schemas/evidence-artifact.d.ts +109 -19
  106. package/dist/core/schemas/evidence-artifact.js +64 -8
  107. package/dist/core/schemas/interface.d.ts +741 -13
  108. package/dist/core/schemas/interface.js +120 -7
  109. package/dist/core/schemas/isolation-manifest.js +16 -9
  110. package/dist/core/schemas/plan.d.ts +329 -3
  111. package/dist/core/schemas/plan.js +89 -3
  112. package/dist/core/schemas/pointer.d.ts +47 -1
  113. package/dist/core/schemas/pointer.js +89 -8
  114. package/dist/core/schemas/port-messages.d.ts +194 -10
  115. package/dist/core/schemas/port-messages.js +73 -6
  116. package/dist/core/schemas/probe-body.d.ts +18 -0
  117. package/dist/core/schemas/probe-body.js +13 -0
  118. package/dist/core/schemas/probe-qualification.d.ts +168 -0
  119. package/dist/core/schemas/probe-qualification.js +106 -0
  120. package/dist/core/schemas/probe.d.ts +431 -0
  121. package/dist/core/schemas/probe.js +6 -2
  122. package/dist/core/schemas/scoring-policy.d.ts +1 -0
  123. package/dist/core/schemas/scoring-policy.js +6 -1
  124. package/dist/core/schemas/sealed-evaluator-brief.d.ts +1 -0
  125. package/dist/core/schemas/sealed-evaluator-brief.js +4 -1
  126. package/dist/core/schemas/sealed-run-record.d.ts +161 -12
  127. package/dist/core/schemas/sealed-run-record.js +92 -15
  128. package/dist/core/schemas/sensitivity-witness.d.ts +108 -6
  129. package/dist/core/schemas/sensitivity-witness.js +61 -5
  130. package/dist/core/score/binding-order.d.ts +31 -0
  131. package/dist/core/score/binding-order.js +88 -0
  132. package/dist/core/score/bindings.d.ts +93 -0
  133. package/dist/core/score/bindings.js +309 -0
  134. package/dist/core/score/ladder-table.d.ts +23 -0
  135. package/dist/core/score/ladder-table.js +109 -0
  136. package/dist/core/score/ladder.d.ts +229 -0
  137. package/dist/core/score/ladder.js +464 -0
  138. package/dist/core/score/mode-agreement.d.ts +30 -0
  139. package/dist/core/score/mode-agreement.js +16 -0
  140. package/dist/core/score/outcome-table.d.ts +17 -0
  141. package/dist/core/score/outcome-table.js +172 -0
  142. package/dist/core/score/outcome.d.ts +466 -0
  143. package/dist/core/score/outcome.js +562 -0
  144. package/dist/core/score/qualification.d.ts +83 -0
  145. package/dist/core/score/qualification.js +645 -0
  146. package/dist/core/score/quotation.d.ts +56 -0
  147. package/dist/core/score/quotation.js +226 -0
  148. package/dist/core/score/reduce-trials.d.ts +80 -0
  149. package/dist/core/score/reduce-trials.js +90 -0
  150. package/dist/core/score/score.d.ts +72 -0
  151. package/dist/core/score/score.js +607 -0
  152. package/dist/core/score/selection.d.ts +80 -0
  153. package/dist/core/score/selection.js +98 -0
  154. package/dist/core/score/strength.d.ts +58 -0
  155. package/dist/core/score/strength.js +227 -0
  156. package/dist/core/score/witness.d.ts +138 -0
  157. package/dist/core/score/witness.js +320 -0
  158. package/dist/core/seal/derived-reference.d.ts +2 -9
  159. package/dist/core/seal/derived-reference.js +293 -46
  160. package/dist/core/seal/plan-index.d.ts +18 -3
  161. package/dist/core/seal/plan-index.js +44 -8
  162. package/dist/core/seal/seal.js +8 -3
  163. package/dist/core/stage-contracts.d.ts +62 -2
  164. package/dist/index.d.ts +1 -1
  165. package/dist/index.js +1 -1
  166. package/dist/ports/environment-probe-port.d.ts +60 -4
  167. package/dist/testing/index.d.ts +2 -0
  168. package/dist/testing/index.js +1 -0
  169. package/dist/testing/probe-conformance.d.ts +29 -0
  170. package/dist/testing/probe-conformance.js +34 -5
  171. package/package.json +12 -3
  172. package/schemas/eval-contract.schema.json +1787 -797
  173. package/schemas/evidence-artifact.schema.json +126 -9
  174. package/schemas/isolation-manifest.schema.json +17 -10
  175. package/schemas/probe.schema.json +636 -5
  176. package/schemas/rubric.schema.json +1 -1
  177. package/schemas/scoring-policy.schema.json +8 -1
  178. package/schemas/sealed-evaluator-brief.schema.json +11 -1
  179. package/schemas/sealed-run-record.schema.json +314 -40
@@ -82,15 +82,45 @@ export const SiblingGroups = z.strictObject({
82
82
  operations: z.array(z.array(Identifier).min(SIBLING_GROUP_MINIMUM)),
83
83
  parameters: z.array(z.array(KeyName).min(SIBLING_GROUP_MINIMUM)),
84
84
  });
85
+ /**
86
+ * A valueless test-data declaration, keyed by name. `kind` stays opaque for
87
+ * the reason `ScopedResource` above already records: no AD supplies a value
88
+ * space, and inventing one is the unshaped-declaration defect in reverse.
89
+ */
90
+ const TestDataDeclaration = z.strictObject({ kind: z.string().min(1) });
85
91
  export const TestData = z.strictObject({
86
92
  setup: z.string().nullable(),
87
93
  cleanup: z.string().nullable(),
94
+ principals: z
95
+ .record(Identifier, TestDataDeclaration)
96
+ .nullable()
97
+ .describe("Owed item 3: the principals a `{ principal }` input binding may name. Caller-keyed by name, which makes a duplicate declaration unrepresentable, and valueless, since AD-19 forbids a credential value in a declaration and AD-18 keeps the name an opaque label. `null`, `{}`, and a populated map are three distinct answers, on `referenceSets`' own reasoning. A binding naming a key absent here still parses; it fires `undeclared-mandatory-input` at compile time in strict mode, because a cross-subtree constraint reaching from `interactionPlan` into this field cannot survive the export. Required, not optional, which makes this and `resources` below together the eval contract's `schemaVersion` 2 -> 3 BREAKING bump under AD-11, whose rule is that \"adding an optional field is a `schemaVersion` bump recorded in the field's own description; removing or retyping is breaking\". `null` is the legal spelling for a contract declaring none, but `TestData` is a `strictObject` and the key itself must be present, so no version-2 contract parses."),
98
+ resources: z
99
+ .record(Identifier, TestDataDeclaration)
100
+ .nullable()
101
+ .describe("Test-data resources, declared the same way as `principals` above. Any entry fires `scoped-reference-resolves-forbidden` at compile time exactly as a `scopedResources` entry does: a resource the contract points the evaluator at is a scoped reference wherever it is written down (AD-16). Required on the same terms as `principals`, and the other half of the eval contract's `schemaVersion` 2 -> 3 BREAKING bump under AD-11: `null` is the empty spelling and the key is mandatory."),
88
102
  });
89
103
  export const Budgets = z.strictObject({
90
104
  maxToolCalls: z.int().min(0),
91
105
  maxWallClockMinutes: z.int().min(0),
92
106
  maxCostUsd: UnsignedDecimalString.describe('Money, so AD-36 carries it as a string in a declared format rather than as a JSON number. Constrained to the unsigned form: a negative ceiling is not a ceiling.'),
93
107
  });
108
+ /**
109
+ * The one `schemaVersion` this build reads.
110
+ *
111
+ * AD-11 says "readers accept an equal `schemaVersion` only and throw
112
+ * `schema-version-mismatch` outside that", and puts the comparison on the
113
+ * reader rather than in the schema: `lineage.ts` records that a `z.literal`
114
+ * would turn a version-2 artifact into an anonymous parse failure instead of
115
+ * AD-28's dedicated fault. That left the rule stated everywhere and performed
116
+ * nowhere for this artifact, so a contract stamped 3 parsed and compiled clean
117
+ * and its stale version travelled into the scoring version, which is the one
118
+ * number AD-11 exists to keep comparable.
119
+ *
120
+ * `compile` is the reader that performs it. The constant lives here beside the
121
+ * schema whose version it names, so the bump and the constant are one edit.
122
+ */
123
+ export const EVAL_CONTRACT_SCHEMA_VERSION = 4;
94
124
  export const EvalContract = z
95
125
  .strictObject({
96
126
  // AD-11's schemaVersion and AD-29's lineage pair, spread from the leaf
@@ -114,7 +144,7 @@ export const EvalContract = z
114
144
  waivers: z.array(Waiver),
115
145
  permittedInterfaces: z
116
146
  .array(PermittedInterface)
117
- .describe('AD-35: logical identifiers only. No entry here is ever a URL, a host, or a port.'),
147
+ .describe("AD-35: logical identifiers only. No entry here is ever a URL, a host, or a port. Discriminated on `kind`, which makes this field the eval contract's `schemaVersion` 3 -> 4 BREAKING bump under AD-11, whose rule is that \"adding an optional field is a `schemaVersion` bump recorded in the field's own description; removing or retyping is breaking\". The `api`, `web`, and `mcp` branches carry the shipped operation shape unchanged, so a version-3 contract's own bytes still parse on them; the `cli` branch carries a command operation, which declares a logical invocation instead of a method and a path template, four command input channels instead of the four transport channels, a nominated output channel for its one response descriptor, and the files it writes."),
118
148
  referenceSets: z
119
149
  .record(Identifier, ReferenceSetDeclaration)
120
150
  .nullable()
@@ -143,5 +173,5 @@ export const EvalContract = z
143
173
  })
144
174
  .meta({
145
175
  id: 'EvalContract',
146
- description: "The Eval Contract. Succeeds the prior-art `eval-contract` schema per AD-24. It carries every declaration AD-19 requires so that AD-31's fourteen relevance and satisfaction predicates are decidable from declarations alone. AD-10's sensitivity witnesses arrived in this version, on each operation, as the additive `schemaVersion` bump AD-11 requires; the bump is recorded in each new field's own description, since no reader in this version declares an expected version constant to compare against.",
176
+ description: "The Eval Contract. Succeeds the prior-art `eval-contract` schema per AD-24. It carries every declaration AD-19 requires so that AD-31's fourteen relevance and satisfaction predicates are decidable from declarations alone. AD-10's sensitivity witnesses arrived on each operation as an additive `schemaVersion` bump; version 4 opens `permittedInterfaces` to a second interface kind, so a contract may describe a system under test that runs behind a command, and widens the interaction pointer's accepted language with the four command input channels and the `artifact` channel. The widening retypes nothing on its own, since every pointer legal under version 3 is still legal; it carries the same version because it ships in the same release as the retypes. Each bump is recorded in its own field's description, and `compile` compares the stamp against `EVAL_CONTRACT_SCHEMA_VERSION` and throws AD-28's `schema-version-mismatch` on anything else.",
147
177
  });
@@ -43,19 +43,22 @@ export type CheckResolutionValue = {
43
43
  */
44
44
  export declare const CheckResolution: z.ZodType<CheckResolutionValue>;
45
45
  /**
46
- * AD-11's five named inputs, transcribed so a reader can recompute the
47
- * digest and see what was compared (AD-8's "by digest and opaque reference,
48
- * never by content or path"). Named object rather than a concatenated tuple:
46
+ * AD-11's identity inputs, transcribed so a reader can recompute the digest
47
+ * and see what was compared (AD-8's "by digest and opaque reference, never
48
+ * by content or path"). Named object rather than a concatenated tuple:
49
49
  * revision 1 let two conforming scorers compute different versions from
50
50
  * identical inputs if they hashed a different ordering. The scorer computes
51
- * the scoring version over this shape.
51
+ * the scoring version over this shape. Six now, not five: `mode` is owed
52
+ * item 4's identity clause, superseding AD-11's original five-field
53
+ * sentence.
52
54
  */
53
- export declare const SCORING_VERSION_INPUT_NAMES: readonly ['contractSchemaVersion', 'corpusDigest', 'fixtureDigest', 'evaluatorConfigurationDigest', 'scoringPolicyDigest'];
55
+ export declare const SCORING_VERSION_INPUT_NAMES: readonly ['contractSchemaVersion', 'corpusDigest', 'fixtureDigest', 'evaluatorConfigurationDigest', 'scoringPolicyDigest', 'mode'];
54
56
  export declare const ScoringVersionInputName: z.ZodEnum<{
55
57
  contractSchemaVersion: "contractSchemaVersion";
56
58
  corpusDigest: "corpusDigest";
57
59
  evaluatorConfigurationDigest: "evaluatorConfigurationDigest";
58
60
  fixtureDigest: "fixtureDigest";
61
+ mode: "mode";
59
62
  scoringPolicyDigest: "scoringPolicyDigest";
60
63
  }>;
61
64
  export declare const ScoringVersionInputs: z.ZodObject<{
@@ -64,11 +67,17 @@ export declare const ScoringVersionInputs: z.ZodObject<{
64
67
  fixtureDigest: z.ZodString;
65
68
  evaluatorConfigurationDigest: z.ZodString;
66
69
  scoringPolicyDigest: z.ZodString;
70
+ mode: z.ZodEnum<{
71
+ "contract-scoring": "contract-scoring";
72
+ production: "production";
73
+ }>;
67
74
  }, z.core.$strict>;
68
75
  export declare const InvalidatedAttempt: z.ZodObject<{
69
76
  attempt: z.ZodInt;
70
77
  reason: z.ZodString;
71
78
  }, z.core.$strict>;
79
+ /** exported so the trial-set reducer names this shape without importing Zod. */
80
+ export type InvalidatedAttempt = z.infer<typeof InvalidatedAttempt>;
72
81
  /**
73
82
  * AD-6: "Every artifact records its trial count, its invalidated attempts, and
74
83
  * each attempt's reason, including on a PASS." None of the three is nullable,
@@ -83,6 +92,8 @@ export declare const Trials: z.ZodObject<{
83
92
  reason: z.ZodString;
84
93
  }, z.core.$strict>>;
85
94
  }, z.core.$strict>;
95
+ /** exported so the ladder names this shape without importing Zod. */
96
+ export type Trials = z.infer<typeof Trials>;
86
97
  export declare const Outcome: z.ZodObject<{
87
98
  oracleId: z.ZodString;
88
99
  probeId: z.ZodNullable<z.ZodString>;
@@ -119,6 +130,8 @@ export declare const Outcome: z.ZodObject<{
119
130
  selectedObservationIds: z.ZodArray<z.ZodString>;
120
131
  checkResolution: z.ZodNullable<z.ZodType<CheckResolutionValue, unknown, z.core.$ZodTypeInternals<CheckResolutionValue, unknown>>>;
121
132
  }, z.core.$strict>;
133
+ /** exported so the dominance comparator names this shape without importing Zod. */
134
+ export type Outcome = z.infer<typeof Outcome>;
122
135
  export declare const CoverageGap: z.ZodObject<{
123
136
  rule: z.ZodString;
124
137
  relevancePredicate: z.ZodString;
@@ -132,11 +145,54 @@ export declare const CoverageGap: z.ZodObject<{
132
145
  }, z.core.$strict>;
133
146
  /** the record as a type, so `core/coverage/` names it without importing Zod. */
134
147
  export type CoverageGap = z.infer<typeof CoverageGap>;
148
+ /**
149
+ * Owed item 5's record for an ingested `defect` finding citing no oracle:
150
+ * AD-23 already retains the finding rather than discarding it, but nothing
151
+ * downstream consumed it until this `schemaVersion`. Mirrors `CoverageGap`'s
152
+ * shape and the `defect`-branch fields on `Finding` it is read from, but
153
+ * carries no relevance or satisfaction predicate: AD-31's coverage gap is a
154
+ * declaration AD-31 could not confirm was satisfied, while an uncited defect
155
+ * finding is a runtime observation an evaluator made outside every declared
156
+ * oracle, with no relevance predicate to name and no satisfaction predicate
157
+ * that failed. This is the version-3 bump: required, not optional, per owed
158
+ * item 5, so a producer that never emits it stops parsing rather than
159
+ * silently under-reporting the gap.
160
+ */
161
+ export declare const UncitedFindingGap: z.ZodObject<{
162
+ findingId: z.ZodString;
163
+ observationIds: z.ZodArray<z.ZodString>;
164
+ quotedEvidence: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
165
+ quote: z.ZodString;
166
+ channel: z.ZodLiteral<"artifact">;
167
+ artifactId: z.ZodString;
168
+ }, z.core.$strict>, z.ZodObject<{
169
+ quote: z.ZodString;
170
+ channel: z.ZodEnum<{
171
+ "call-inputs": "call-inputs";
172
+ "exit-code": "exit-code";
173
+ "response-body": "response-body";
174
+ "response-headers": "response-headers";
175
+ "response-status": "response-status";
176
+ stderr: "stderr";
177
+ stdout: "stdout";
178
+ }>;
179
+ artifactId: z.ZodNull;
180
+ }, z.core.$strict>]>>;
181
+ severity: z.ZodEnum<{
182
+ critical: "critical";
183
+ low: "low";
184
+ material: "material";
185
+ }>;
186
+ }, z.core.$strict>;
187
+ /** exported so `core/score/ladder.ts` names this shape without importing Zod. */
188
+ export type UncitedFindingGap = z.infer<typeof UncitedFindingGap>;
135
189
  export declare const ClassStrength: z.ZodObject<{
136
190
  caught: z.ZodInt;
137
191
  exercised: z.ZodInt;
138
192
  rate: z.ZodNullable<z.ZodNumber>;
139
193
  }, z.core.$strict>;
194
+ /** exported so the rate-vector builder names this shape without importing Zod. */
195
+ export type ClassStrength = z.infer<typeof ClassStrength>;
140
196
  /**
141
197
  * A fixed three-key object instead of a map keyed by probe class. AD-7 is
142
198
  * explicit that "canary probes and clean controls never enter the vector", so
@@ -159,6 +215,8 @@ export declare const StrengthVector: z.ZodObject<{
159
215
  rate: z.ZodNullable<z.ZodNumber>;
160
216
  }, z.core.$strict>>;
161
217
  }, z.core.$strict>;
218
+ /** exported so the rate-vector builder names this shape without importing Zod. */
219
+ export type StrengthVector = z.infer<typeof StrengthVector>;
162
220
  export declare const Strength: z.ZodObject<{
163
221
  denominator: z.ZodString;
164
222
  basis: z.ZodEnum<{
@@ -185,6 +243,8 @@ export declare const Strength: z.ZodObject<{
185
243
  comparable: z.ZodBoolean;
186
244
  note: z.ZodNullable<z.ZodString>;
187
245
  }, z.core.$strict>;
246
+ /** exported so the dominance comparator names this shape without importing Zod. */
247
+ export type Strength = z.infer<typeof Strength>;
188
248
  /**
189
249
  * AD-12's three named checks, transcribed from the same sentence the field
190
250
  * comes from: the package "validates a caller-presented lineage chain (length
@@ -221,13 +281,6 @@ export declare const EvidenceArtifact: z.ZodDiscriminatedUnion<[z.ZodObject<{
221
281
  revisionCount: z.ZodInt;
222
282
  runId: z.ZodString;
223
283
  scoringVersion: z.ZodString;
224
- scoringVersionInputs: z.ZodObject<{
225
- contractSchemaVersion: z.ZodInt;
226
- corpusDigest: z.ZodString;
227
- fixtureDigest: z.ZodString;
228
- evaluatorConfigurationDigest: z.ZodString;
229
- scoringPolicyDigest: z.ZodString;
230
- }, z.core.$strict>;
231
284
  comparabilityKey: z.ZodString;
232
285
  excludedProbeIds: z.ZodArray<z.ZodString>;
233
286
  exitCode: z.ZodInt;
@@ -237,6 +290,7 @@ export declare const EvidenceArtifact: z.ZodDiscriminatedUnion<[z.ZodObject<{
237
290
  corpusDigest: "corpusDigest";
238
291
  evaluatorConfigurationDigest: "evaluatorConfigurationDigest";
239
292
  fixtureDigest: "fixtureDigest";
293
+ mode: "mode";
240
294
  scoringPolicyDigest: "scoringPolicyDigest";
241
295
  }>>;
242
296
  trials: z.ZodObject<{
@@ -331,6 +385,14 @@ export declare const EvidenceArtifact: z.ZodDiscriminatedUnion<[z.ZodObject<{
331
385
  noGap: z.ZodBoolean;
332
386
  }, z.core.$strict>;
333
387
  }, z.core.$strict>;
388
+ scoringVersionInputs: z.ZodObject<{
389
+ contractSchemaVersion: z.ZodInt;
390
+ corpusDigest: z.ZodString;
391
+ fixtureDigest: z.ZodString;
392
+ evaluatorConfigurationDigest: z.ZodString;
393
+ scoringPolicyDigest: z.ZodString;
394
+ mode: z.ZodLiteral<"production">;
395
+ }, z.core.$strict>;
334
396
  mode: z.ZodLiteral<"production">;
335
397
  productionVerdict: z.ZodEnum<{
336
398
  CONCERNS: "CONCERNS";
@@ -344,13 +406,6 @@ export declare const EvidenceArtifact: z.ZodDiscriminatedUnion<[z.ZodObject<{
344
406
  revisionCount: z.ZodInt;
345
407
  runId: z.ZodString;
346
408
  scoringVersion: z.ZodString;
347
- scoringVersionInputs: z.ZodObject<{
348
- contractSchemaVersion: z.ZodInt;
349
- corpusDigest: z.ZodString;
350
- fixtureDigest: z.ZodString;
351
- evaluatorConfigurationDigest: z.ZodString;
352
- scoringPolicyDigest: z.ZodString;
353
- }, z.core.$strict>;
354
409
  comparabilityKey: z.ZodString;
355
410
  excludedProbeIds: z.ZodArray<z.ZodString>;
356
411
  exitCode: z.ZodInt;
@@ -360,6 +415,7 @@ export declare const EvidenceArtifact: z.ZodDiscriminatedUnion<[z.ZodObject<{
360
415
  corpusDigest: "corpusDigest";
361
416
  evaluatorConfigurationDigest: "evaluatorConfigurationDigest";
362
417
  fixtureDigest: "fixtureDigest";
418
+ mode: "mode";
363
419
  scoringPolicyDigest: "scoringPolicyDigest";
364
420
  }>>;
365
421
  trials: z.ZodObject<{
@@ -454,6 +510,14 @@ export declare const EvidenceArtifact: z.ZodDiscriminatedUnion<[z.ZodObject<{
454
510
  noGap: z.ZodBoolean;
455
511
  }, z.core.$strict>;
456
512
  }, z.core.$strict>;
513
+ scoringVersionInputs: z.ZodObject<{
514
+ contractSchemaVersion: z.ZodInt;
515
+ corpusDigest: z.ZodString;
516
+ fixtureDigest: z.ZodString;
517
+ evaluatorConfigurationDigest: z.ZodString;
518
+ scoringPolicyDigest: z.ZodString;
519
+ mode: z.ZodLiteral<"contract-scoring">;
520
+ }, z.core.$strict>;
457
521
  mode: z.ZodLiteral<"contract-scoring">;
458
522
  contractVerdict: z.ZodEnum<{
459
523
  CONCERNS: "CONCERNS";
@@ -461,6 +525,32 @@ export declare const EvidenceArtifact: z.ZodDiscriminatedUnion<[z.ZodObject<{
461
525
  PASS: "PASS";
462
526
  WAIVED: "WAIVED";
463
527
  }>;
528
+ uncitedFindingGaps: z.ZodArray<z.ZodObject<{
529
+ findingId: z.ZodString;
530
+ observationIds: z.ZodArray<z.ZodString>;
531
+ quotedEvidence: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
532
+ quote: z.ZodString;
533
+ channel: z.ZodLiteral<"artifact">;
534
+ artifactId: z.ZodString;
535
+ }, z.core.$strict>, z.ZodObject<{
536
+ quote: z.ZodString;
537
+ channel: z.ZodEnum<{
538
+ "call-inputs": "call-inputs";
539
+ "exit-code": "exit-code";
540
+ "response-body": "response-body";
541
+ "response-headers": "response-headers";
542
+ "response-status": "response-status";
543
+ stderr: "stderr";
544
+ stdout: "stdout";
545
+ }>;
546
+ artifactId: z.ZodNull;
547
+ }, z.core.$strict>]>>;
548
+ severity: z.ZodEnum<{
549
+ critical: "critical";
550
+ low: "low";
551
+ material: "material";
552
+ }>;
553
+ }, z.core.$strict>>;
464
554
  systemRecommendationRecorded: z.ZodEnum<{
465
555
  CONCERNS: "CONCERNS";
466
556
  FAIL: "FAIL";
@@ -3,7 +3,7 @@ import { z } from 'zod';
3
3
  import { Severity } from './eval-contract.js';
4
4
  import { lineageFields } from './lineage.js';
5
5
  import { Digest, FindingId, Identifier, OracleId, ProbeId, } from './primitives.js';
6
- import { OracleDispositionValue } from './sealed-run-record.js';
6
+ import { OracleDispositionValue, QuotedEvidence, RunMode, } from './sealed-run-record.js';
7
7
  import { EvaluatorRecommendation, Verdict } from './verdict.js';
8
8
  /**
9
9
  * AD-6's closed twelve. Exported so a later reader can walk the list
@@ -52,12 +52,14 @@ export const CheckResolution = z
52
52
  description: "One node of an oracle's `check` tree as it resolved. AD-4's resolution is three-valued rather than two, and the introduction vocabulary has exactly one member because AD-4 closes the introduction set at one: an empty collection. `null` where the resolution is not `insufficient-evidence`. A leaf carries an empty `children` array.",
53
53
  });
54
54
  /**
55
- * AD-11's five named inputs, transcribed so a reader can recompute the
56
- * digest and see what was compared (AD-8's "by digest and opaque reference,
57
- * never by content or path"). Named object rather than a concatenated tuple:
55
+ * AD-11's identity inputs, transcribed so a reader can recompute the digest
56
+ * and see what was compared (AD-8's "by digest and opaque reference, never
57
+ * by content or path"). Named object rather than a concatenated tuple:
58
58
  * revision 1 let two conforming scorers compute different versions from
59
59
  * identical inputs if they hashed a different ordering. The scorer computes
60
- * the scoring version over this shape.
60
+ * the scoring version over this shape. Six now, not five: `mode` is owed
61
+ * item 4's identity clause, superseding AD-11's original five-field
62
+ * sentence.
61
63
  */
62
64
  export const SCORING_VERSION_INPUT_NAMES = [
63
65
  'contractSchemaVersion',
@@ -65,14 +67,44 @@ export const SCORING_VERSION_INPUT_NAMES = [
65
67
  'fixtureDigest',
66
68
  'evaluatorConfigurationDigest',
67
69
  'scoringPolicyDigest',
70
+ 'mode',
68
71
  ];
69
72
  export const ScoringVersionInputName = z.enum(SCORING_VERSION_INPUT_NAMES);
73
+ const SCORING_VERSION_MODE_DESCRIPTION = "Owed item 4's identity clause: mode enters AD-11's scoring version, superseding AD-11's five-field sentence. Read from the sealed run record, never re-derived, so two runs scored under one mode never collide with a version computed for the other. Required, not optional, which makes this the evidence artifact's `schemaVersion` 1 -> 2 BREAKING bump under AD-11, whose rule is that \"adding an optional field is a `schemaVersion` bump recorded in the field's own description; removing or retyping is breaking\". A version-1 artifact carries five scoring-version inputs where this one carries six, so it does not parse, and no version computed before the bump compares with one computed after it.";
70
74
  export const ScoringVersionInputs = z.strictObject({
71
75
  contractSchemaVersion: z.int().min(1),
72
76
  corpusDigest: Digest,
73
77
  fixtureDigest: Digest,
74
78
  evaluatorConfigurationDigest: Digest,
75
79
  scoringPolicyDigest: Digest,
80
+ mode: RunMode.describe(SCORING_VERSION_MODE_DESCRIPTION),
81
+ });
82
+ /**
83
+ * `scoringVersionInputs.mode` narrowed to the one value that agrees with
84
+ * `EvidenceArtifact`'s own branch discriminant (AD-11, AD-32), rather than a
85
+ * `.refine()` comparing the two fields. A refinement never exports, so the
86
+ * published document would keep admitting the disagreement, and the
87
+ * corpus-mutation generator synthesises witnesses for an untaken `oneOf`
88
+ * branch straight from that branch's own JSON Schema with no knowledge of a
89
+ * Zod-only cross-field rule -- verified: it produced two dozen genuine
90
+ * `zod=false published=true` disagreements this way. Narrowing the schema
91
+ * itself removes the gap at its source: a synthesised example for a
92
+ * `const`-typed field can only be that one value.
93
+ *
94
+ * Two named consts rather than one generic builder: a `<M extends
95
+ * RunModeValue>(mode: M)` helper builds each schema correctly, but TypeScript
96
+ * fails to preserve the per-call-site literal through `EvidenceArtifact`'s
97
+ * `z.discriminatedUnion` inference, so a fixture assigning the wrong branch's
98
+ * `mode` here compiles instead of erroring. Two concrete literals close that
99
+ * gap by construction; there is nothing generic left for the checker to lose.
100
+ */
101
+ const productionScoringVersionInputs = ScoringVersionInputs.extend({
102
+ mode: z.literal('production').describe(SCORING_VERSION_MODE_DESCRIPTION),
103
+ });
104
+ const contractScoringVersionInputs = ScoringVersionInputs.extend({
105
+ mode: z
106
+ .literal('contract-scoring')
107
+ .describe(SCORING_VERSION_MODE_DESCRIPTION),
76
108
  });
77
109
  export const InvalidatedAttempt = z.strictObject({
78
110
  attempt: z.int().min(1),
@@ -115,6 +147,25 @@ export const CoverageGap = z.strictObject({
115
147
  satisfied: z.boolean(),
116
148
  severity: Severity,
117
149
  });
150
+ /**
151
+ * Owed item 5's record for an ingested `defect` finding citing no oracle:
152
+ * AD-23 already retains the finding rather than discarding it, but nothing
153
+ * downstream consumed it until this `schemaVersion`. Mirrors `CoverageGap`'s
154
+ * shape and the `defect`-branch fields on `Finding` it is read from, but
155
+ * carries no relevance or satisfaction predicate: AD-31's coverage gap is a
156
+ * declaration AD-31 could not confirm was satisfied, while an uncited defect
157
+ * finding is a runtime observation an evaluator made outside every declared
158
+ * oracle, with no relevance predicate to name and no satisfaction predicate
159
+ * that failed. This is the version-3 bump: required, not optional, per owed
160
+ * item 5, so a producer that never emits it stops parsing rather than
161
+ * silently under-reporting the gap.
162
+ */
163
+ export const UncitedFindingGap = z.strictObject({
164
+ findingId: FindingId,
165
+ observationIds: z.array(Identifier).min(1),
166
+ quotedEvidence: z.array(QuotedEvidence).min(1),
167
+ severity: Severity,
168
+ });
118
169
  export const ClassStrength = z.strictObject({
119
170
  caught: z.int().min(0),
120
171
  exercised: z.int().min(0),
@@ -178,7 +229,7 @@ export const Remediation = z.strictObject({
178
229
  const evidenceCommonFields = {
179
230
  ...lineageFields,
180
231
  runId: z.string().min(1),
181
- scoringVersion: Digest.describe('AD-11: computed by the scorer over the five named inputs below and never caller-supplied.'),
232
+ scoringVersion: Digest.describe('AD-11: computed by the scorer over the six named inputs below and never caller-supplied.'),
182
233
  scoringVersionInputs: ScoringVersionInputs,
183
234
  comparabilityKey: Digest.describe("AD-7's declared key: the scoring policy digest plus the corpus digest restricted to the probes both results cover. Deliberately weaker than the scoring version, so adding a probe narrows a comparison rather than voiding every prior result."),
184
235
  excludedProbeIds: z
@@ -192,7 +243,7 @@ const evidenceCommonFields = {
192
243
  .describe('Every condition that fired, in AD-21 terms. Free text by design: the rungs are prose in AD-21 and assigning them identifiers would be minting a vocabulary that AD has not. Each member is non-empty, on the same reasoning that `InvalidatedAttempt.reason` is: a condition that names itself with nothing has not been recorded. An empty array is legal and is what a PASS with no firing condition carries.'),
193
244
  callerAttestedInputs: z
194
245
  .array(ScoringVersionInputName)
195
- .describe('Which of the five scoring-version inputs were caller-attested rather than computed by this package. An enum over the five key names rather than free strings, because AD-32 requires the artifact to state *which* inputs were attested and an unconstrained string cannot be checked against anything. AD-11 names three of the five as caller-attested; the enum admits any subset so a stricter or looser integration stays representable.'),
246
+ .describe('Which of the six scoring-version inputs were caller-attested rather than computed by this package. An enum over the six key names rather than free strings, because AD-32 requires the artifact to state *which* inputs were attested and an unconstrained string cannot be checked against anything. AD-11 names three of the six as caller-attested; the enum admits any subset so a stricter or looser integration stays representable. `mode` is the one member that is not a choice: `ScoringVersionInputs.mode` is read from the sealed run record and never re-derived, so a list omitting it is a misdeclaration rather than a stricter integration. The schema admits that shape and the constraint ledger records why; `core/emit` always names it.'),
196
247
  trials: Trials,
197
248
  outcomes: z.array(Outcome),
198
249
  uncitedFindings: z
@@ -212,6 +263,7 @@ export const EvidenceArtifact = z
212
263
  z
213
264
  .strictObject({
214
265
  ...evidenceCommonFields,
266
+ scoringVersionInputs: productionScoringVersionInputs,
215
267
  mode: z.literal('production'),
216
268
  productionVerdict: Verdict,
217
269
  })
@@ -219,8 +271,12 @@ export const EvidenceArtifact = z
219
271
  z
220
272
  .strictObject({
221
273
  ...evidenceCommonFields,
274
+ scoringVersionInputs: contractScoringVersionInputs,
222
275
  mode: z.literal('contract-scoring'),
223
276
  contractVerdict: Verdict,
277
+ uncitedFindingGaps: z
278
+ .array(UncitedFindingGap)
279
+ .describe("Owed item 5's rung record, contract-scoring only: one entry per uncited `defect` finding, per `core/score/outcome.ts`'s `uncitedDefectFindingGaps`. Required, not optional, which makes this the `schemaVersion` 2 -> 3 BREAKING bump under AD-11: an empty array is legal and is what a run with no uncited defect finding carries, but the key itself must be present. Never on the production branch, where the ladder signal alone is enough and this key would fail `strictObject`'s `unrecognized_keys` rule."),
224
280
  systemRecommendationRecorded: EvaluatorRecommendation.describe("The evaluator's recommendation about the SYSTEM, recorded and never promoted. On a knowingly defective probe a system-directed FAIL is an input rather than a signal about the contract."),
225
281
  systemRecommendationNote: z.string().nullable(),
226
282
  })
@@ -228,5 +284,5 @@ export const EvidenceArtifact = z
228
284
  ])
229
285
  .meta({
230
286
  id: 'EvidenceArtifact',
231
- description: "The scored output, owned by `emit` per AD-24, with no prior art; `score` produces the outcome and verdict values it serializes. The two modes are separate branches because AD-21 requires that the production verdict and the contract verdict never share a field. This expresses that settled sentence and no more: Owed item 4's remaining half stays open, namely mode being fixed before ingest and entering AD-11's identity inputs rather than appearing first here; and the Sealed Run Record still carries no mode.",
287
+ description: 'The scored output, owned by `emit` per AD-24, with no prior art; `score` produces the outcome and verdict values it serializes. The two modes are separate branches because AD-21 requires that the production verdict and the contract verdict never share a field. Mode is no longer first stated here: the Sealed Run Record now carries a required `mode`, where AD-21\'s "fixed before ingest" puts it, so this artifact restates a mode the sealed record already fixed and is never the source. Owed item 4 is closed as of this schemaVersion: `mode` is `ScoringVersionInputs`\'s sixth field, `core/score/ladder.ts` carries `ProductionAssessment`/`ContractAssessment` and their own total ladders, and `core/score/mode-agreement.ts` rejects a `production` record paired with a `contract-scoring` artifact in both directions as an AD-32 cross-artifact disagreement. That check is a hand-written function at the assembly boundary rather than a schema refinement, since no single schema sees both artifacts; `emit` is its one caller, immediately before returning the artifact it just built. Owed item 5 is closed as of this schemaVersion too: the contract-scoring branch carries a required `uncitedFindingGaps`, and both ladders in `core/score/ladder.ts` gain a shared `uncited-defect-finding` CONCERNS row over `AssessmentCommon.uncitedDefectFindings`, so an ingested defect finding citing no oracle now resolves at least CONCERNS instead of routing nowhere.',
232
288
  });