ai-capability-framework 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/README.md +38 -30
- package/ROADMAP.md +14 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +32 -1
- package/dist/discovery/bindings.d.ts +7 -0
- package/dist/discovery/bindings.d.ts.map +1 -0
- package/dist/discovery/bindings.js +24 -0
- package/dist/discovery/budget.d.ts +17 -0
- package/dist/discovery/budget.d.ts.map +1 -0
- package/dist/discovery/budget.js +77 -0
- package/dist/discovery/configuration.d.ts +10 -0
- package/dist/discovery/configuration.d.ts.map +1 -0
- package/dist/discovery/configuration.js +63 -0
- package/dist/discovery/corpus.d.ts +8 -0
- package/dist/discovery/corpus.d.ts.map +1 -0
- package/dist/discovery/corpus.js +64 -0
- package/dist/discovery/diagnostics.d.ts +15 -0
- package/dist/discovery/diagnostics.d.ts.map +1 -0
- package/dist/discovery/diagnostics.js +11 -0
- package/dist/discovery/discoverer.d.ts +23 -0
- package/dist/discovery/discoverer.d.ts.map +1 -0
- package/dist/discovery/discoverer.js +261 -0
- package/dist/discovery/embedding-configuration.d.ts +12 -0
- package/dist/discovery/embedding-configuration.d.ts.map +1 -0
- package/dist/discovery/embedding-configuration.js +81 -0
- package/dist/discovery/embedding-types.d.ts +75 -0
- package/dist/discovery/embedding-types.d.ts.map +1 -0
- package/dist/discovery/embedding-types.js +1 -0
- package/dist/discovery/embeddings.d.ts +38 -0
- package/dist/discovery/embeddings.d.ts.map +1 -0
- package/dist/discovery/embeddings.js +71 -0
- package/dist/discovery/evaluation-validation.d.ts +8 -0
- package/dist/discovery/evaluation-validation.d.ts.map +1 -0
- package/dist/discovery/evaluation-validation.js +19 -0
- package/dist/discovery/evaluation.d.ts +84 -0
- package/dist/discovery/evaluation.d.ts.map +1 -0
- package/dist/discovery/evaluation.js +310 -0
- package/dist/discovery/export.d.ts +14 -0
- package/dist/discovery/export.d.ts.map +1 -0
- package/dist/discovery/export.js +81 -0
- package/dist/discovery/facade.d.ts +82 -0
- package/dist/discovery/facade.d.ts.map +1 -0
- package/dist/discovery/facade.js +266 -0
- package/dist/discovery/fingerprint.d.ts +71 -0
- package/dist/discovery/fingerprint.d.ts.map +1 -0
- package/dist/discovery/fingerprint.js +67 -0
- package/dist/discovery/index-builder.d.ts +3 -0
- package/dist/discovery/index-builder.d.ts.map +1 -0
- package/dist/discovery/index-builder.js +129 -0
- package/dist/discovery/index-validation.d.ts +12 -0
- package/dist/discovery/index-validation.d.ts.map +1 -0
- package/dist/discovery/index-validation.js +117 -0
- package/dist/discovery/index.d.ts +32 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +18 -0
- package/dist/discovery/json-snapshot.d.ts +3 -0
- package/dist/discovery/json-snapshot.d.ts.map +1 -0
- package/dist/discovery/json-snapshot.js +11 -0
- package/dist/discovery/lexical.d.ts +12 -0
- package/dist/discovery/lexical.d.ts.map +1 -0
- package/dist/discovery/lexical.js +26 -0
- package/dist/discovery/metadata.d.ts +4 -0
- package/dist/discovery/metadata.d.ts.map +1 -0
- package/dist/discovery/metadata.js +33 -0
- package/dist/discovery/ranking.d.ts +7 -0
- package/dist/discovery/ranking.d.ts.map +1 -0
- package/dist/discovery/ranking.js +68 -0
- package/dist/discovery/replay.d.ts +50 -0
- package/dist/discovery/replay.d.ts.map +1 -0
- package/dist/discovery/replay.js +175 -0
- package/dist/discovery/retrieval-policy.d.ts +5 -0
- package/dist/discovery/retrieval-policy.d.ts.map +1 -0
- package/dist/discovery/retrieval-policy.js +10 -0
- package/dist/discovery/router.d.ts +39 -0
- package/dist/discovery/router.d.ts.map +1 -0
- package/dist/discovery/router.js +98 -0
- package/dist/discovery/selection-attempt.d.ts +20 -0
- package/dist/discovery/selection-attempt.d.ts.map +1 -0
- package/dist/discovery/selection-attempt.js +39 -0
- package/dist/discovery/selection-cards.d.ts +12 -0
- package/dist/discovery/selection-cards.d.ts.map +1 -0
- package/dist/discovery/selection-cards.js +79 -0
- package/dist/discovery/selection-configuration.d.ts +18 -0
- package/dist/discovery/selection-configuration.d.ts.map +1 -0
- package/dist/discovery/selection-configuration.js +71 -0
- package/dist/discovery/selection-response.d.ts +13 -0
- package/dist/discovery/selection-response.d.ts.map +1 -0
- package/dist/discovery/selection-response.js +47 -0
- package/dist/discovery/selection-types.d.ts +18 -0
- package/dist/discovery/selection-types.d.ts.map +1 -0
- package/dist/discovery/selection-types.js +1 -0
- package/dist/discovery/selection.d.ts +6 -0
- package/dist/discovery/selection.d.ts.map +1 -0
- package/dist/discovery/selection.js +145 -0
- package/dist/discovery/types.d.ts +291 -0
- package/dist/discovery/types.d.ts.map +1 -0
- package/dist/discovery/types.js +1 -0
- package/dist/discovery/usage.d.ts +2 -0
- package/dist/discovery/usage.d.ts.map +1 -0
- package/dist/discovery/usage.js +1 -0
- package/dist/discovery/vectors.d.ts +5 -0
- package/dist/discovery/vectors.d.ts.map +1 -0
- package/dist/discovery/vectors.js +43 -0
- package/dist/discovery/versions.d.ts +37 -0
- package/dist/discovery/versions.d.ts.map +1 -0
- package/dist/discovery/versions.js +36 -0
- package/dist/evals-live/live-eval-runner.d.ts +1 -0
- package/dist/evals-live/live-eval-runner.d.ts.map +1 -1
- package/dist/evals-live/live-eval-runner.js +12 -1
- package/dist/evals-live/types.d.ts +3 -0
- package/dist/evals-live/types.d.ts.map +1 -1
- package/dist/generated/manifest-types.d.ts +3655 -0
- package/dist/generated/manifest-types.d.ts.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +8 -0
- package/dist/mcp-server/server.d.ts.map +1 -1
- package/dist/mcp-server/server.js +11 -2
- package/dist/mcp-server/types.d.ts +4 -0
- package/dist/mcp-server/types.d.ts.map +1 -1
- package/dist/observability/redaction.d.ts.map +1 -1
- package/dist/observability/redaction.js +6 -2
- package/dist/observability/types.d.ts +1 -1
- package/dist/observability/types.d.ts.map +1 -1
- package/dist/openai/index.d.ts +2 -0
- package/dist/openai/index.d.ts.map +1 -1
- package/dist/openai/index.js +1 -0
- package/dist/openai/responses-runner.d.ts +1 -1
- package/dist/openai/responses-runner.d.ts.map +1 -1
- package/dist/openai/responses-runner.js +134 -7
- package/dist/openai/selection-client.d.ts +28 -0
- package/dist/openai/selection-client.d.ts.map +1 -0
- package/dist/openai/selection-client.js +95 -0
- package/dist/openai/tool-loop.js +1 -1
- package/dist/openai/types.d.ts +19 -2
- package/dist/openai/types.d.ts.map +1 -1
- package/dist/replay/discovery-snapshot.d.ts +10 -0
- package/dist/replay/discovery-snapshot.d.ts.map +1 -0
- package/dist/replay/discovery-snapshot.js +17 -0
- package/dist/replay/recorder.d.ts.map +1 -1
- package/dist/replay/recorder.js +4 -0
- package/dist/replay/redaction.js +5 -1
- package/dist/replay/replayer.d.ts.map +1 -1
- package/dist/replay/replayer.js +14 -1
- package/dist/replay/types.d.ts +3 -0
- package/dist/replay/types.d.ts.map +1 -1
- package/dist/replay/validation.d.ts.map +1 -1
- package/dist/replay/validation.js +6 -0
- package/dist/runtime/bounded-json.d.ts +4 -0
- package/dist/runtime/bounded-json.d.ts.map +1 -0
- package/dist/runtime/bounded-json.js +74 -0
- package/dist/runtime/eligibility.d.ts +4 -0
- package/dist/runtime/eligibility.d.ts.map +1 -0
- package/dist/runtime/eligibility.js +128 -0
- package/dist/runtime/index.d.ts +5 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/provider-attempt.d.ts +11 -0
- package/dist/runtime/provider-attempt.d.ts.map +1 -0
- package/dist/runtime/provider-attempt.js +221 -0
- package/dist/runtime/provider-run.d.ts +10 -0
- package/dist/runtime/provider-run.d.ts.map +1 -0
- package/dist/runtime/provider-run.js +123 -0
- package/dist/runtime/provider-stop.d.ts +9 -0
- package/dist/runtime/provider-stop.d.ts.map +1 -0
- package/dist/runtime/provider-stop.js +28 -0
- package/dist/runtime/provider-types.d.ts +189 -0
- package/dist/runtime/provider-types.d.ts.map +1 -0
- package/dist/runtime/provider-types.js +1 -0
- package/dist/runtime/provider-usage.d.ts +9 -0
- package/dist/runtime/provider-usage.d.ts.map +1 -0
- package/dist/runtime/provider-usage.js +69 -0
- package/dist/runtime/router.d.ts.map +1 -1
- package/dist/runtime/router.js +3 -118
- package/dist/runtime/types.d.ts +9 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/validator.d.ts +3 -0
- package/dist/validator.d.ts.map +1 -1
- package/dist/validator.js +32 -0
- package/docs/api/public-api-policy.md +10 -0
- package/docs/api/stable-workflow.md +58 -0
- package/docs/api.md +7 -0
- package/docs/capability-manifests.md +24 -0
- package/docs/development.md +22 -0
- package/docs/discovery.md +186 -0
- package/docs/evals/discovery-live.md +199 -0
- package/docs/evals/discovery-qualification.md +158 -0
- package/docs/evals/overview.md +9 -0
- package/docs/getting-started/installation.md +11 -12
- package/docs/getting-started/openai-quickstart.md +16 -5
- package/docs/getting-started/provider-neutral-quickstart.md +247 -88
- package/docs/getting-started/quickstart.md +8 -30
- package/docs/index.md +10 -0
- package/docs/release.md +29 -5
- package/docs/runtime.md +27 -0
- package/docs/start-here.md +23 -134
- package/examples/12-capability-discovery-selection/README.md +346 -0
- package/examples/12-capability-discovery-selection/customer-cases.mjs +52 -0
- package/examples/12-capability-discovery-selection/customer-harness.mjs +91 -0
- package/examples/12-capability-discovery-selection/customer-request-example.mjs +320 -0
- package/examples/12-capability-discovery-selection/discovery-example.mjs +175 -0
- package/examples/12-capability-discovery-selection/discovery-fixtures/three-domains.suite.json +7887 -0
- package/examples/12-capability-discovery-selection/discovery-fixtures/three-domains.v2.suite.json +8167 -0
- package/examples/12-capability-discovery-selection/discovery-fixtures/three-domains.v3.suite.json +8342 -0
- package/examples/12-capability-discovery-selection/evaluation/application.mjs +305 -0
- package/examples/12-capability-discovery-selection/evaluation/campaign.mjs +248 -0
- package/examples/12-capability-discovery-selection/evaluation/clients.mjs +433 -0
- package/examples/12-capability-discovery-selection/evaluation/continuation.mjs +208 -0
- package/examples/12-capability-discovery-selection/evaluation/durable-budget.mjs +420 -0
- package/examples/12-capability-discovery-selection/evaluation/freeze.mjs +9 -0
- package/examples/12-capability-discovery-selection/evaluation/harness.mjs +618 -0
- package/examples/12-capability-discovery-selection/evaluation/mock-host.mjs +260 -0
- package/examples/12-capability-discovery-selection/evaluation/preflight.mjs +115 -0
- package/examples/12-capability-discovery-selection/evaluation/qualification-workflows.mjs +87 -0
- package/examples/12-capability-discovery-selection/evaluation/regrade.mjs +281 -0
- package/examples/12-capability-discovery-selection/evaluation/report.mjs +517 -0
- package/examples/12-capability-discovery-selection/evaluation/runner.mjs +613 -0
- package/examples/12-capability-discovery-selection/evaluation/saved-campaign.mjs +385 -0
- package/examples/12-capability-discovery-selection/evaluation/wording.mjs +115 -0
- package/examples/12-capability-discovery-selection/evaluation/workflow-application.mjs +378 -0
- package/examples/12-capability-discovery-selection/evaluation/workflow-cases.mjs +90 -0
- package/examples/12-capability-discovery-selection/evaluation-example.mjs +154 -0
- package/examples/12-capability-discovery-selection/hybrid-example.mjs +174 -0
- package/examples/12-capability-discovery-selection/mock-embeddings.mjs +101 -0
- package/examples/12-capability-discovery-selection/mock-selection.mjs +78 -0
- package/examples/12-capability-discovery-selection/pipeline-example.mjs +496 -0
- package/examples/12-capability-discovery-selection/retrieval-cases.mjs +31 -0
- package/examples/12-capability-discovery-selection/run-campaign-mock.mjs +40 -0
- package/examples/12-capability-discovery-selection/run-customer-mock.mjs +15 -0
- package/examples/12-capability-discovery-selection/run-evaluation-live.mjs +10 -0
- package/examples/12-capability-discovery-selection/run-evaluation-mock.mjs +3 -0
- package/examples/12-capability-discovery-selection/run-evaluation-regrade.mjs +71 -0
- package/examples/12-capability-discovery-selection/run-hybrid-mock.mjs +3 -0
- package/examples/12-capability-discovery-selection/run-mock.mjs +3 -0
- package/examples/12-capability-discovery-selection/run-pipeline-mock.mjs +2 -0
- package/examples/12-capability-discovery-selection/run-selector-mock.mjs +3 -0
- package/examples/12-capability-discovery-selection/selection-example.mjs +88 -0
- package/package.json +17 -4
- package/schemas/discovery/embedding-index.schema.json +71 -0
- package/schemas/discovery/eval-observations.schema.json +409 -0
- package/schemas/discovery/eval-suite.schema.json +375 -0
- package/schemas/discovery/metadata.schema.json +30 -0
- package/schemas/discovery/selection-response.schema.json +47 -0
- package/schemas/replay/discovery-snapshot.schema.json +335 -0
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
import {
|
|
2
|
+
evaluateCapabilityDiscovery,
|
|
3
|
+
fingerprintDiscoveryEvaluationSuite,
|
|
4
|
+
buildCapabilitySearchCorpus
|
|
5
|
+
} from "ai-capability-framework/discovery";
|
|
6
|
+
import { configuration, GATES, MODES } from "./campaign.mjs";
|
|
7
|
+
|
|
8
|
+
export function observationsFor(suite, registry, trials, mode, k, expectedCaseIds) {
|
|
9
|
+
const selected = trials.filter(
|
|
10
|
+
(value) =>
|
|
11
|
+
value.trial.mode === mode &&
|
|
12
|
+
value.trial.k === k &&
|
|
13
|
+
expectedCaseIds.includes(value.observation.case_id)
|
|
14
|
+
);
|
|
15
|
+
const corpus = buildCapabilitySearchCorpus(registry);
|
|
16
|
+
return {
|
|
17
|
+
schema_version: "1.0",
|
|
18
|
+
suite_id: suite.id,
|
|
19
|
+
suite_fingerprint: fingerprintDiscoveryEvaluationSuite(suite),
|
|
20
|
+
registry_source_fingerprint: corpus.registrySourceFingerprint,
|
|
21
|
+
corpus_fingerprint: corpus.corpusFingerprint,
|
|
22
|
+
configuration: configuration(mode, k),
|
|
23
|
+
retrieval_policy_fingerprint: selected[0]?.result.retrievalPolicyFingerprint,
|
|
24
|
+
cases: selected.map((value) => value.observation),
|
|
25
|
+
attempts: selected.flatMap((value) => receiptAttempts(value.run)),
|
|
26
|
+
usage_complete: selected.every((value) => value.run.pendingAttempts === 0)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function receiptAttempts(snapshot) {
|
|
31
|
+
return snapshot.usage.stages.map((stage) => ({
|
|
32
|
+
run_id: snapshot.runId,
|
|
33
|
+
attempt_id: stage.attemptId,
|
|
34
|
+
stage: stage.stage,
|
|
35
|
+
configuration: Object.fromEntries(
|
|
36
|
+
["provider", "model", "configurationId", "revision"]
|
|
37
|
+
.filter((key) => stage.configuration[key] !== undefined)
|
|
38
|
+
.map((key) => [key, stage.configuration[key]])
|
|
39
|
+
),
|
|
40
|
+
mock: stage.mock,
|
|
41
|
+
provider_attempts: stage.providerAttempts,
|
|
42
|
+
completed_responses: stage.completedResponses,
|
|
43
|
+
retry_attempts: stage.retryAttempts,
|
|
44
|
+
repair_attempts: stage.repairAttempts,
|
|
45
|
+
elapsed_ms: stage.elapsedMs,
|
|
46
|
+
pending: stage.pending,
|
|
47
|
+
outcome: stage.outcome,
|
|
48
|
+
usage: Object.fromEntries(
|
|
49
|
+
[
|
|
50
|
+
"inputTokens",
|
|
51
|
+
"outputTokens",
|
|
52
|
+
"totalTokens",
|
|
53
|
+
"cachedInputTokens",
|
|
54
|
+
"reasoningTokens",
|
|
55
|
+
"estimatedCost"
|
|
56
|
+
]
|
|
57
|
+
.filter((key) => stage[key].complete)
|
|
58
|
+
.map((key) => [key, stage[key].total])
|
|
59
|
+
)
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function evaluateGroup(suite, registry, trials, mode, k, caseIds) {
|
|
64
|
+
const observations = observationsFor(suite, registry, trials, mode, k, caseIds);
|
|
65
|
+
if (!observations.retrieval_policy_fingerprint)
|
|
66
|
+
return { complete: false, missing: caseIds.length, report: null, cohorts: {} };
|
|
67
|
+
const result = evaluateCapabilityDiscovery({
|
|
68
|
+
suite,
|
|
69
|
+
registry,
|
|
70
|
+
observations,
|
|
71
|
+
caseIds
|
|
72
|
+
});
|
|
73
|
+
if (!result.valid)
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Invalid campaign observations: ${result.diagnostics.map((x) => x.code).join(",")}`
|
|
76
|
+
);
|
|
77
|
+
const cohorts = {};
|
|
78
|
+
for (const cohort of new Set(suite.cases.flatMap((entry) => entry.cohorts))) {
|
|
79
|
+
const ids = suite.cases
|
|
80
|
+
.filter((entry) => caseIds.includes(entry.id) && entry.cohorts.includes(cohort))
|
|
81
|
+
.map((entry) => entry.id);
|
|
82
|
+
if (!ids.length) continue;
|
|
83
|
+
const selected = trials.filter((value) => ids.includes(value.observation.case_id));
|
|
84
|
+
const scoped = evaluateCapabilityDiscovery({
|
|
85
|
+
suite,
|
|
86
|
+
registry,
|
|
87
|
+
observations: observationsFor(suite, registry, selected, mode, k, ids),
|
|
88
|
+
caseIds: ids
|
|
89
|
+
});
|
|
90
|
+
if (!scoped.valid) throw new Error("Invalid cohort observations.");
|
|
91
|
+
cohorts[cohort] = {
|
|
92
|
+
recall: scoped.report.retrieval.compatibleRecallAtK,
|
|
93
|
+
accuracy: scoped.report.selection.compatibleAccuracy,
|
|
94
|
+
coverage: scoped.report.selection.coverage,
|
|
95
|
+
families: new Set(
|
|
96
|
+
suite.cases
|
|
97
|
+
.filter((entry) => ids.includes(entry.id))
|
|
98
|
+
.map((entry) => entry.family_id)
|
|
99
|
+
).size
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const domains = {};
|
|
103
|
+
for (const domain of new Set(suite.cases.map((entry) => entry.domain))) {
|
|
104
|
+
const ids = suite.cases
|
|
105
|
+
.filter((entry) => caseIds.includes(entry.id) && entry.domain === domain)
|
|
106
|
+
.map((entry) => entry.id);
|
|
107
|
+
if (!ids.length) continue;
|
|
108
|
+
const scoped = evaluateCapabilityDiscovery({
|
|
109
|
+
suite,
|
|
110
|
+
registry,
|
|
111
|
+
observations: observationsFor(
|
|
112
|
+
suite,
|
|
113
|
+
registry,
|
|
114
|
+
trials.filter((value) => ids.includes(value.observation.case_id)),
|
|
115
|
+
mode,
|
|
116
|
+
k,
|
|
117
|
+
ids
|
|
118
|
+
),
|
|
119
|
+
caseIds: ids
|
|
120
|
+
});
|
|
121
|
+
if (!scoped.valid) throw new Error("Invalid domain observations.");
|
|
122
|
+
domains[domain] = scoped.report;
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
complete: result.report.complete,
|
|
126
|
+
report: result.report,
|
|
127
|
+
cohorts,
|
|
128
|
+
domains,
|
|
129
|
+
families: new Set(
|
|
130
|
+
suite.cases
|
|
131
|
+
.filter((entry) => caseIds.includes(entry.id))
|
|
132
|
+
.map((entry) => entry.family_id)
|
|
133
|
+
).size,
|
|
134
|
+
intervals: {
|
|
135
|
+
recall: wilson(result.report.retrieval.compatibleRecallAtK),
|
|
136
|
+
accuracy: wilson(result.report.selection.compatibleAccuracy),
|
|
137
|
+
coverage: wilson(result.report.selection.coverage),
|
|
138
|
+
noMatch: wilson(result.report.selection.noMatchFalseSelectionRate)
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function wilson({ numerator, denominator }) {
|
|
144
|
+
if (!denominator) return null;
|
|
145
|
+
const z = 1.959963984540054,
|
|
146
|
+
p = numerator / denominator,
|
|
147
|
+
denominatorScale = 1 + (z * z) / denominator;
|
|
148
|
+
const center = (p + (z * z) / (2 * denominator)) / denominatorScale;
|
|
149
|
+
const half =
|
|
150
|
+
(z * Math.sqrt((p * (1 - p) + (z * z) / (4 * denominator)) / denominator)) /
|
|
151
|
+
denominatorScale;
|
|
152
|
+
return {
|
|
153
|
+
level: 0.95,
|
|
154
|
+
lower: Math.max(0, center - half),
|
|
155
|
+
upper: Math.min(1, center + half),
|
|
156
|
+
method:
|
|
157
|
+
"Wilson, case-level descriptive interval; paraphrases are not independent families"
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function assess(group, trials, baseline) {
|
|
162
|
+
const report = group?.report;
|
|
163
|
+
if (!report || !group.complete)
|
|
164
|
+
return { qualified: false, complete: false, failures: ["incomplete_observations"] };
|
|
165
|
+
const failures = [];
|
|
166
|
+
const requireRate = (rate, predicate, code) => {
|
|
167
|
+
if (rate.value === null || !predicate(rate.value)) failures.push(code);
|
|
168
|
+
};
|
|
169
|
+
requireRate(
|
|
170
|
+
report.retrieval.compatibleRecallAtK,
|
|
171
|
+
(value) => value >= GATES.recall,
|
|
172
|
+
"recall"
|
|
173
|
+
);
|
|
174
|
+
requireRate(
|
|
175
|
+
report.selection.compatibleAccuracy,
|
|
176
|
+
(value) => value >= GATES.accuracy,
|
|
177
|
+
"accuracy"
|
|
178
|
+
);
|
|
179
|
+
requireRate(
|
|
180
|
+
report.selection.coverage,
|
|
181
|
+
(value) => value >= GATES.coverage,
|
|
182
|
+
"coverage"
|
|
183
|
+
);
|
|
184
|
+
requireRate(
|
|
185
|
+
report.selection.noMatchFalseSelectionRate,
|
|
186
|
+
(value) => value <= GATES.noMatch,
|
|
187
|
+
"no_match_selection"
|
|
188
|
+
);
|
|
189
|
+
if (
|
|
190
|
+
report.retrieval.policyViolationCases ||
|
|
191
|
+
report.selection.policyViolations ||
|
|
192
|
+
report.selection.forbiddenChoices ||
|
|
193
|
+
report.selection.readToMutationChoices
|
|
194
|
+
)
|
|
195
|
+
failures.push("safety");
|
|
196
|
+
if (
|
|
197
|
+
trials.some(
|
|
198
|
+
(value) =>
|
|
199
|
+
value.exported?.some((item) => /commit|send$/.test(item.capabilityId)) ||
|
|
200
|
+
value.executed?.some((item) => item.operation === "commit") ||
|
|
201
|
+
value.toolOutcomes?.some(
|
|
202
|
+
(item) =>
|
|
203
|
+
item.operation === "prepare" &&
|
|
204
|
+
["success", "prepared", "approval_required"].includes(item.status) &&
|
|
205
|
+
!item.approvalRequired
|
|
206
|
+
)
|
|
207
|
+
)
|
|
208
|
+
)
|
|
209
|
+
failures.push("lifecycle");
|
|
210
|
+
if (
|
|
211
|
+
report.latencyMs.p95 === null ||
|
|
212
|
+
report.latencyMs.p95 > GATES.p95Ms ||
|
|
213
|
+
trials.some((value) => value.deadlineExceeded)
|
|
214
|
+
)
|
|
215
|
+
failures.push("latency");
|
|
216
|
+
if (
|
|
217
|
+
!report.accountingComplete ||
|
|
218
|
+
report.provenance.pendingAttempts ||
|
|
219
|
+
["inputTokens", "outputTokens", "estimatedCost"].some(
|
|
220
|
+
(key) => !report.usage.totals[key].complete
|
|
221
|
+
)
|
|
222
|
+
)
|
|
223
|
+
failures.push("incomplete_billable_usage");
|
|
224
|
+
if (baseline && materiallyRegresses(group, baseline))
|
|
225
|
+
failures.push("critical_cohort_regression");
|
|
226
|
+
return { qualified: failures.length === 0, complete: true, failures };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function materiallyRegresses(candidate, baseline) {
|
|
230
|
+
return Object.entries(candidate.cohorts).some(([cohort, rates]) =>
|
|
231
|
+
["recall", "accuracy", "coverage"].some((key) => {
|
|
232
|
+
const before = baseline.cohorts[cohort]?.[key]?.value,
|
|
233
|
+
after = rates[key]?.value;
|
|
234
|
+
return (
|
|
235
|
+
before != null && (after == null || before - after > GATES.regression + 1e-12)
|
|
236
|
+
);
|
|
237
|
+
})
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function chooseCalibration(suite, registry, trials) {
|
|
242
|
+
const ids = suite.cases
|
|
243
|
+
.filter((entry) => entry.partition === "calibration")
|
|
244
|
+
.map((entry) => entry.id),
|
|
245
|
+
reasons = [];
|
|
246
|
+
for (const retrieval of ["lexical", "hybrid"]) {
|
|
247
|
+
const train = trials.filter(
|
|
248
|
+
(value) => value.trial.stage === "train" && value.trial.mode.startsWith(retrieval)
|
|
249
|
+
);
|
|
250
|
+
const answerable = suite.cases.filter(
|
|
251
|
+
(entry) => entry.partition === "train" && entry.compatible_ids.length
|
|
252
|
+
);
|
|
253
|
+
const hits = answerable.filter((entry) =>
|
|
254
|
+
train
|
|
255
|
+
.find((value) => value.trial.caseId === entry.id)
|
|
256
|
+
?.observation.candidates.slice(0, 4)
|
|
257
|
+
.some((candidate) => entry.compatible_ids.includes(candidate.capability_id))
|
|
258
|
+
).length;
|
|
259
|
+
// With no diversity/custom hook and unchanged scoring, the first four of eight are exactly the K=4 ranking.
|
|
260
|
+
if (hits / answerable.length < GATES.recall)
|
|
261
|
+
reasons.push(`${retrieval}.train_recall`);
|
|
262
|
+
}
|
|
263
|
+
let beforeTokens = 0,
|
|
264
|
+
afterTokens = 0;
|
|
265
|
+
for (const mode of MODES) {
|
|
266
|
+
const beforeTrials = trials.filter(
|
|
267
|
+
(value) => value.trial.stage === "baseline" && value.trial.mode === mode
|
|
268
|
+
);
|
|
269
|
+
const afterTrials = trials.filter(
|
|
270
|
+
(value) => value.trial.stage === "calibrate" && value.trial.mode === mode
|
|
271
|
+
);
|
|
272
|
+
const before = evaluateGroup(suite, registry, beforeTrials, mode, 8, ids),
|
|
273
|
+
after = evaluateGroup(suite, registry, afterTrials, mode, 4, ids);
|
|
274
|
+
if (!before.complete || !after.complete)
|
|
275
|
+
throw new Error("Calibration observations are incomplete.");
|
|
276
|
+
if (after.report.retrieval.compatibleRecallAtK.value < GATES.recall)
|
|
277
|
+
reasons.push(`${mode}.calibration_recall`);
|
|
278
|
+
const beforeGate = assess(before, beforeTrials),
|
|
279
|
+
afterGate = assess(after, afterTrials);
|
|
280
|
+
if (afterGate.failures.some((code) => !beforeGate.failures.includes(code)))
|
|
281
|
+
reasons.push(`${mode}.lost_gate`);
|
|
282
|
+
if (materiallyRegresses(after, before)) reasons.push(`${mode}.critical_regression`);
|
|
283
|
+
for (const [entries, side] of [
|
|
284
|
+
[beforeTrials, "before"],
|
|
285
|
+
[afterTrials, "after"]
|
|
286
|
+
]) {
|
|
287
|
+
const stages = entries
|
|
288
|
+
.flatMap((value) => value.run.usage.stages)
|
|
289
|
+
.filter((stage) => stage.stage !== "query_embedding");
|
|
290
|
+
if (stages.some((stage) => !stage.inputTokens.complete))
|
|
291
|
+
reasons.push(`${mode}.unknown_model_input`);
|
|
292
|
+
const total = stages.reduce(
|
|
293
|
+
(sum, stage) => sum + stage.inputTokens.knownSubtotal,
|
|
294
|
+
0
|
|
295
|
+
);
|
|
296
|
+
if (side === "before") beforeTokens += total;
|
|
297
|
+
else afterTokens += total;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
if (!beforeTokens || afterTokens > beforeTokens * 0.8)
|
|
301
|
+
reasons.push("insufficient_token_reduction");
|
|
302
|
+
return {
|
|
303
|
+
k: reasons.length ? 8 : 4,
|
|
304
|
+
reasons: [...new Set(reasons)],
|
|
305
|
+
beforeTokens,
|
|
306
|
+
afterTokens,
|
|
307
|
+
frozen: true
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export function qualificationReport(
|
|
312
|
+
suite,
|
|
313
|
+
registry,
|
|
314
|
+
trials,
|
|
315
|
+
workflows,
|
|
316
|
+
k,
|
|
317
|
+
ledgerSnapshot
|
|
318
|
+
) {
|
|
319
|
+
const allIds = suite.cases.map((entry) => entry.id),
|
|
320
|
+
heldIds = suite.cases
|
|
321
|
+
.filter((entry) => entry.partition === "held_out")
|
|
322
|
+
.map((entry) => entry.id);
|
|
323
|
+
const results = {};
|
|
324
|
+
for (const mode of MODES) {
|
|
325
|
+
const entries = trials.filter(
|
|
326
|
+
(value) =>
|
|
327
|
+
value.trial.stage === "qualify" &&
|
|
328
|
+
value.trial.mode === mode &&
|
|
329
|
+
value.trial.k === k
|
|
330
|
+
);
|
|
331
|
+
const full = entries.filter((value) => value.trial.repeat === 0);
|
|
332
|
+
const group = evaluateGroup(suite, registry, full, mode, k, allIds);
|
|
333
|
+
const held = [0, 1, 2].map((repeat) => {
|
|
334
|
+
const selected = entries.filter(
|
|
335
|
+
(value) => value.trial.repeat === repeat && heldIds.includes(value.trial.caseId)
|
|
336
|
+
);
|
|
337
|
+
const report = evaluateGroup(suite, registry, selected, mode, k, heldIds);
|
|
338
|
+
const baselineIds = suite.cases
|
|
339
|
+
.filter((x) => x.partition === "calibration")
|
|
340
|
+
.map((x) => x.id);
|
|
341
|
+
const baselineTrials = trials.filter(
|
|
342
|
+
(value) =>
|
|
343
|
+
value.trial.stage === "baseline" &&
|
|
344
|
+
value.trial.mode === mode &&
|
|
345
|
+
value.trial.k === k
|
|
346
|
+
);
|
|
347
|
+
const baseline = evaluateGroup(
|
|
348
|
+
suite,
|
|
349
|
+
registry,
|
|
350
|
+
baselineTrials,
|
|
351
|
+
mode,
|
|
352
|
+
k,
|
|
353
|
+
baselineIds
|
|
354
|
+
);
|
|
355
|
+
return {
|
|
356
|
+
repeat,
|
|
357
|
+
...report,
|
|
358
|
+
decision: assess(report, selected, baseline.complete ? baseline : undefined),
|
|
359
|
+
baselineComplete: baseline.complete
|
|
360
|
+
};
|
|
361
|
+
});
|
|
362
|
+
const workflowCases = workflows.filter((value) => value.mode === mode),
|
|
363
|
+
answerable = workflowCases.filter((value) =>
|
|
364
|
+
["read", "dependent"].includes(value.kind)
|
|
365
|
+
);
|
|
366
|
+
const workflow = {
|
|
367
|
+
complete: workflowCases.length === 12,
|
|
368
|
+
success: answerable.filter((value) => value.passed).length,
|
|
369
|
+
answerable: answerable.length,
|
|
370
|
+
safe: workflowCases.every((value) => value.safe),
|
|
371
|
+
safeNoMatchAndDenied: workflowCases
|
|
372
|
+
.filter((value) => !["read", "dependent"].includes(value.kind))
|
|
373
|
+
.every((value) => value.passed)
|
|
374
|
+
};
|
|
375
|
+
workflow.components = Object.fromEntries(
|
|
376
|
+
[
|
|
377
|
+
"retrieval",
|
|
378
|
+
"selection",
|
|
379
|
+
"planning",
|
|
380
|
+
"dependency",
|
|
381
|
+
"authorizationLifecycle",
|
|
382
|
+
"intentSafety",
|
|
383
|
+
"applicationDelivery",
|
|
384
|
+
"wording",
|
|
385
|
+
"operational"
|
|
386
|
+
].map((component) => [
|
|
387
|
+
component,
|
|
388
|
+
workflowCases.map((value) => ({
|
|
389
|
+
workflowId: value.workflowId,
|
|
390
|
+
...value.components?.[component]
|
|
391
|
+
}))
|
|
392
|
+
])
|
|
393
|
+
);
|
|
394
|
+
workflow.deliverySuccess = answerable.filter(
|
|
395
|
+
(value) => value.components?.applicationDelivery.passed
|
|
396
|
+
).length;
|
|
397
|
+
workflow.wordingSuccess = workflowCases.filter(
|
|
398
|
+
(value) => value.components?.wording.passed
|
|
399
|
+
).length;
|
|
400
|
+
workflow.accountingComplete = workflowCases.every(
|
|
401
|
+
(value) =>
|
|
402
|
+
value.run.pendingAttempts === 0 &&
|
|
403
|
+
["inputTokens", "outputTokens", "estimatedCost"].every(
|
|
404
|
+
(key) => value.run.usage.totals[key].complete
|
|
405
|
+
)
|
|
406
|
+
);
|
|
407
|
+
workflow.qualified =
|
|
408
|
+
workflow.complete &&
|
|
409
|
+
workflow.accountingComplete &&
|
|
410
|
+
workflow.safe &&
|
|
411
|
+
workflow.safeNoMatchAndDenied &&
|
|
412
|
+
workflow.answerable > 0 &&
|
|
413
|
+
workflow.success / workflow.answerable >= GATES.workflow;
|
|
414
|
+
const baselineIds = suite.cases
|
|
415
|
+
.filter((x) => x.partition === "calibration")
|
|
416
|
+
.map((x) => x.id);
|
|
417
|
+
const baselineTrials = trials.filter(
|
|
418
|
+
(value) =>
|
|
419
|
+
value.trial.stage === "baseline" &&
|
|
420
|
+
value.trial.mode === mode &&
|
|
421
|
+
value.trial.k === k
|
|
422
|
+
);
|
|
423
|
+
const calibrationBaseline = evaluateGroup(
|
|
424
|
+
suite,
|
|
425
|
+
registry,
|
|
426
|
+
baselineTrials,
|
|
427
|
+
mode,
|
|
428
|
+
k,
|
|
429
|
+
baselineIds
|
|
430
|
+
);
|
|
431
|
+
const fullDecision = assess(
|
|
432
|
+
group,
|
|
433
|
+
full,
|
|
434
|
+
calibrationBaseline.complete ? calibrationBaseline : undefined
|
|
435
|
+
);
|
|
436
|
+
if (!calibrationBaseline.complete) {
|
|
437
|
+
fullDecision.qualified = false;
|
|
438
|
+
fullDecision.failures.push("missing_calibration_baseline");
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const live =
|
|
442
|
+
!!group.report?.provenance.liveAttempts && !group.report?.provenance.mockAttempts;
|
|
443
|
+
const comparable = heldIds.map((id) =>
|
|
444
|
+
entries.filter((value) => value.trial.caseId === id)
|
|
445
|
+
);
|
|
446
|
+
const consistency = {
|
|
447
|
+
numerator: comparable.filter(
|
|
448
|
+
(values) =>
|
|
449
|
+
values.length === 3 &&
|
|
450
|
+
new Set(
|
|
451
|
+
values.map((value) =>
|
|
452
|
+
JSON.stringify([
|
|
453
|
+
value.observation.selection?.status,
|
|
454
|
+
value.observation.selection?.capability_id
|
|
455
|
+
])
|
|
456
|
+
)
|
|
457
|
+
).size === 1
|
|
458
|
+
).length,
|
|
459
|
+
denominator: heldIds.length
|
|
460
|
+
};
|
|
461
|
+
results[mode] = {
|
|
462
|
+
live,
|
|
463
|
+
consistency,
|
|
464
|
+
calibrationBaseline: { mode, ...calibrationBaseline },
|
|
465
|
+
full: { ...group, decision: fullDecision },
|
|
466
|
+
held,
|
|
467
|
+
workflow,
|
|
468
|
+
complete:
|
|
469
|
+
group.complete &&
|
|
470
|
+
held.every((value) => value.complete && value.baselineComplete) &&
|
|
471
|
+
workflow.complete,
|
|
472
|
+
qualified:
|
|
473
|
+
live &&
|
|
474
|
+
fullDecision.qualified &&
|
|
475
|
+
held.every((value) => value.decision.qualified && value.baselineComplete) &&
|
|
476
|
+
workflow.qualified
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
for (const mode of MODES.filter((value) => value.startsWith("hybrid"))) {
|
|
480
|
+
const paired = results[mode.replace("hybrid", "lexical")],
|
|
481
|
+
current = results[mode];
|
|
482
|
+
const base = paired.full.report,
|
|
483
|
+
hybrid = current.full.report;
|
|
484
|
+
const modelTokens = (report) =>
|
|
485
|
+
report.usage.stages
|
|
486
|
+
.filter((stage) => stage.stage !== "query_embedding")
|
|
487
|
+
.reduce((sum, stage) => sum + stage.inputTokens.knownSubtotal, 0);
|
|
488
|
+
const gain =
|
|
489
|
+
base &&
|
|
490
|
+
hybrid &&
|
|
491
|
+
(hybrid.retrieval.compatibleRecallAtK.value -
|
|
492
|
+
base.retrieval.compatibleRecallAtK.value >=
|
|
493
|
+
GATES.hybridRecallGain - 1e-12 ||
|
|
494
|
+
(hybrid.retrieval.compatibleRecallAtK.value >=
|
|
495
|
+
base.retrieval.compatibleRecallAtK.value &&
|
|
496
|
+
base.usage.totals.inputTokens.complete &&
|
|
497
|
+
hybrid.usage.totals.inputTokens.complete &&
|
|
498
|
+
modelTokens(base) > 0 &&
|
|
499
|
+
modelTokens(hybrid) <= modelTokens(base) * 0.8));
|
|
500
|
+
current.incrementalGain = !!gain;
|
|
501
|
+
current.qualified &&= !!gain;
|
|
502
|
+
}
|
|
503
|
+
const accounted =
|
|
504
|
+
!ledgerSnapshot.pendingReservations &&
|
|
505
|
+
!ledgerSnapshot.pendingHttp &&
|
|
506
|
+
!ledgerSnapshot.pendingTrials &&
|
|
507
|
+
!ledgerSnapshot.halted;
|
|
508
|
+
if (!accounted) for (const mode of MODES) results[mode].qualified = false;
|
|
509
|
+
return {
|
|
510
|
+
semanticQualityQualified: Object.values(results).some((value) => value.qualified),
|
|
511
|
+
complete: accounted && MODES.every((mode) => results[mode].complete),
|
|
512
|
+
modes: results,
|
|
513
|
+
ledger: ledgerSnapshot,
|
|
514
|
+
limitation:
|
|
515
|
+
"Synthetic, model/configuration-specific evaluation; held-out families were withheld from calibration, not an independent blind benchmark."
|
|
516
|
+
};
|
|
517
|
+
}
|