@aiwg/cli 2026.9.21 → 2026.10.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/agentic/code/providers/capability-matrix.yaml +2 -1
- package/dist/src/artifacts/cli.js +23 -18
- package/dist/src/artifacts/discovery-shadow-evaluator.js +177 -0
- package/dist/src/artifacts/discovery-shadow.js +195 -0
- package/dist/src/artifacts/fortemi-core-query-adapter.js +6 -2
- package/dist/src/artifacts/index-builder.js +47 -9
- package/dist/src/artifacts/query-engine.js +108 -5
- package/dist/src/artifacts/types.js +1 -0
- package/dist/src/cli/handlers/decision.js +88 -0
- package/dist/src/cli/handlers/gates.js +154 -0
- package/dist/src/cli/handlers/index.js +5 -1
- package/dist/src/cli/handlers/sessions.js +10 -7
- package/dist/src/cli/handlers/utilities.js +20 -0
- package/dist/src/config/aiwg-config.js +15 -2
- package/dist/src/decision/acceptance.js +25 -0
- package/dist/src/decision/adapters/jev.js +24 -2
- package/dist/src/decision/calibration/registry.js +9 -0
- package/dist/src/decision/compose.js +74 -15
- package/dist/src/decision/context-live-promotion.js +344 -0
- package/dist/src/decision/context-live-qualification.js +591 -0
- package/dist/src/decision/context-pruning.js +847 -0
- package/dist/src/decision/driver.js +430 -0
- package/dist/src/decision/egress-live-qualification.js +874 -0
- package/dist/src/decision/ensemble/contract.js +64 -1
- package/dist/src/decision/ensemble/index.js +1 -0
- package/dist/src/decision/ensemble/report.js +8 -42
- package/dist/src/decision/ensemble/runtime.js +571 -0
- package/dist/src/decision/ensemble-study/artifacts.js +85 -0
- package/dist/src/decision/ensemble-study/calibration.js +443 -0
- package/dist/src/decision/ensemble-study/corpus.js +229 -0
- package/dist/src/decision/ensemble-study/multifact-artifacts.js +23 -0
- package/dist/src/decision/ensemble-study/multifact-study.js +596 -0
- package/dist/src/decision/ensemble-study/multifact.js +241 -0
- package/dist/src/decision/ensemble-study/protocol.js +77 -0
- package/dist/src/decision/ensemble-study/score.js +462 -0
- package/dist/src/decision/ensemble-study/staged.js +87 -0
- package/dist/src/decision/ensemble-study/statistics.js +84 -0
- package/dist/src/decision/evaluate.js +227 -14
- package/dist/src/decision/export.js +4 -0
- package/dist/src/decision/feature-export.js +1074 -0
- package/dist/src/decision/graph-index.js +16 -0
- package/dist/src/decision/graph-live-qualification.js +1041 -0
- package/dist/src/decision/graph-live-workload.js +245 -0
- package/dist/src/decision/graph-skill-bridge.js +21 -3
- package/dist/src/decision/heldout/calibration.js +140 -0
- package/dist/src/decision/heldout/collector.js +430 -0
- package/dist/src/decision/heldout/contract.js +309 -0
- package/dist/src/decision/heldout/d29-generator-ids.js +12 -0
- package/dist/src/decision/heldout/d29-passage-baseline-v2.js +93 -0
- package/dist/src/decision/heldout/d29-passage-baseline-v3.js +100 -0
- package/dist/src/decision/heldout/d29-passage-baseline.js +66 -0
- package/dist/src/decision/heldout/d29-pools-v8.js +575 -0
- package/dist/src/decision/heldout/d29-pools.js +288 -0
- package/dist/src/decision/heldout/d29-v6.js +169 -0
- package/dist/src/decision/heldout/d29-v7.js +202 -0
- package/dist/src/decision/heldout/d29-v8.js +586 -0
- package/dist/src/decision/heldout/generator-registry.js +67 -0
- package/dist/src/decision/heldout/generators.js +696 -0
- package/dist/src/decision/heldout/index.js +8 -0
- package/dist/src/decision/heldout/journal.js +346 -0
- package/dist/src/decision/heldout/study-generators.js +64 -0
- package/dist/src/decision/heldout/types.js +2 -0
- package/dist/src/decision/host-policy.js +61 -0
- package/dist/src/decision/index.js +11 -0
- package/dist/src/decision/interop-profile.v1.json +112 -0
- package/dist/src/decision/interop.js +653 -0
- package/dist/src/decision/issue-triage/index.js +3 -0
- package/dist/src/decision/issue-triage/runtime.js +1069 -0
- package/dist/src/decision/issue-triage/types.js +2 -0
- package/dist/src/decision/patterns/catalog.js +28 -8
- package/dist/src/decision/patterns/playground.js +28 -11
- package/dist/src/decision/patterns/specs.js +19 -10
- package/dist/src/decision/preprocessed-evidence.js +724 -0
- package/dist/src/decision/qualification/capture.js +8 -2
- package/dist/src/decision/qualification/gate-evidence.js +19 -4
- package/dist/src/decision/qualification/load.js +8 -1
- package/dist/src/decision/qualification/quality.js +57 -49
- package/dist/src/decision/qualification/release.js +76 -3
- package/dist/src/decision/qualification/runner.js +5 -2
- package/dist/src/decision/routing/contract.js +175 -0
- package/dist/src/decision/routing/index.js +5 -0
- package/dist/src/decision/routing/report.js +216 -0
- package/dist/src/decision/routing/runtime.js +685 -0
- package/dist/src/decision/routing/types.js +2 -0
- package/dist/src/decision/sdlc-screening.js +1157 -0
- package/dist/src/decision/sensitivity/comparative.js +154 -0
- package/dist/src/decision/sensitivity/contract.js +218 -0
- package/dist/src/decision/sensitivity/index.js +5 -0
- package/dist/src/decision/sensitivity/runtime.js +912 -0
- package/dist/src/decision/sensitivity/types.js +2 -0
- package/dist/src/decision/validate.js +26 -0
- package/dist/src/extensions/commands/definitions.js +38 -0
- package/dist/src/extensions/manifest.js +44 -0
- package/dist/src/gates/discovery.js +315 -0
- package/dist/src/gates/driver.js +388 -0
- package/dist/src/gates/evaluate.js +719 -0
- package/dist/src/gates/floors.js +255 -0
- package/dist/src/gates/index.js +17 -0
- package/dist/src/gates/providers/evidence.js +38 -0
- package/dist/src/gates/providers/index.js +21 -0
- package/dist/src/gates/providers/isolated-child-source.js +446 -0
- package/dist/src/gates/providers/loader.js +1069 -0
- package/dist/src/gates/providers/paired.js +52 -0
- package/dist/src/gates/providers/proportion.js +60 -0
- package/dist/src/gates/providers/registry.js +40 -0
- package/dist/src/gates/providers/scalar.js +41 -0
- package/dist/src/gates/providers/screening.js +53 -0
- package/dist/src/gates/providers/types.js +25 -0
- package/dist/src/gates/registry.js +1003 -0
- package/dist/src/gates/report.js +102 -0
- package/dist/src/gates/schema.js +56 -0
- package/dist/src/gates/stats/binomial.js +26 -0
- package/dist/src/gates/stats/bootstrap.js +62 -0
- package/dist/src/gates/stats/clopper-pearson.js +95 -0
- package/dist/src/gates/stats/digest.js +26 -0
- package/dist/src/gates/stats/error.js +5 -0
- package/dist/src/gates/stats/index.js +9 -0
- package/dist/src/gates/stats/normal.js +35 -0
- package/dist/src/gates/stats/paired.js +120 -0
- package/dist/src/gates/stats/splits.js +30 -0
- package/dist/src/gates/types.js +8 -0
- package/dist/src/governance/redaction.js +14 -4
- package/dist/src/mcp/muse-native-config.mjs +123 -0
- package/dist/src/mcp/tools/decision.mjs +188 -0
- package/dist/src/mcp/tools/subsystems.mjs +2 -0
- package/dist/src/providers/capability-matrix.yaml +2 -1
- package/dist/src/providers/provider-definitions.js +2 -1
- package/dist/src/sessions/adapters/muse.js +336 -39
- package/dist/src/sessions/batch-import.js +7 -0
- package/dist/src/sessions/workspace-discovery.js +13 -2
- package/package.json +1 -1
- package/schemas/decision/ConformalFrozenOpenData.v2.schema.json +371 -0
- package/schemas/decision/ConformalOpenDataReport.v2.schema.json +421 -0
- package/schemas/decision/ConformalPreregistration.v2.schema.json +529 -0
- package/schemas/decision/ContextPruningCandidate.v1.schema.json +47 -0
- package/schemas/decision/ContextPruningEvaluationReport.v1.schema.json +758 -0
- package/schemas/decision/ContextPruningPreregistration.v1.schema.json +175 -0
- package/schemas/decision/ContextPruningReceipt.v1.schema.json +72 -0
- package/schemas/decision/D17Multifact.v1.schema.json +1851 -0
- package/schemas/decision/D17StudyAnalysis.v1.schema.json +42 -0
- package/schemas/decision/D17StudyAnalysis.v2.schema.json +51 -0
- package/schemas/decision/D17StudyCalibration.v1.schema.json +819 -0
- package/schemas/decision/D17StudyDryRun.v1.schema.json +169 -0
- package/schemas/decision/D17StudyDryRun.v2.schema.json +239 -0
- package/schemas/decision/D17StudyGold.v1.schema.json +108 -0
- package/schemas/decision/D17StudyGuide.v1.schema.json +63 -0
- package/schemas/decision/D17StudyNativeTemplates.v1.schema.json +619 -0
- package/schemas/decision/D17StudyProtocol.v1.schema.json +241 -0
- package/schemas/decision/D17StudyReport.v1.schema.json +902 -0
- package/schemas/decision/D17StudyReport.v2.schema.json +1319 -0
- package/schemas/decision/D17StudyReview.v1.schema.json +175 -0
- package/schemas/decision/D17StudySplits.v1.schema.json +217 -0
- package/schemas/decision/D29Study.v1.schema.json +1903 -0
- package/schemas/decision/D29Study.v2.schema.json +1344 -0
- package/schemas/decision/D29Study.v3.schema.json +609 -0
- package/schemas/decision/D29Study.v4.schema.json +1133 -0
- package/schemas/decision/D29Study.v6.schema.json +1205 -0
- package/schemas/decision/D29Study.v7.schema.json +1471 -0
- package/schemas/decision/D29Study.v8.schema.json +671 -0
- package/schemas/decision/D29Study.v9.schema.json +778 -0
- package/schemas/decision/DecisionComparativeReplayAuditSample.v1.schema.json +137 -0
- package/schemas/decision/DecisionComparativeReplayCorpus.v1.schema.json +258 -0
- package/schemas/decision/DecisionComparativeReplayFreeze.v1.schema.json +74 -0
- package/schemas/decision/DecisionComparativeReplayGold.v1.schema.json +50 -0
- package/schemas/decision/DecisionComparativeReplayGoldAsset.v1.schema.json +37 -0
- package/schemas/decision/DecisionComparativeReplayIntegrity.v1.schema.json +81 -0
- package/schemas/decision/DecisionComparativeReplayMembers.v1.schema.json +52 -0
- package/schemas/decision/DecisionComparativeReplayPreregistration.v1.schema.json +113 -0
- package/schemas/decision/DecisionComparativeReplayReport.v1.schema.json +407 -0
- package/schemas/decision/DecisionComparativeReplayReviewPackets.v1.schema.json +260 -0
- package/schemas/decision/DecisionComparativeReplaySplit.v1.schema.json +84 -0
- package/schemas/decision/DecisionFeatureObservation.v1.schema.json +564 -0
- package/schemas/decision/DecisionFeatureSet.v1.schema.json +155 -0
- package/schemas/decision/DecisionInteropMapping.v1.schema.json +85 -0
- package/schemas/decision/DecisionIssueTriageEvaluationManifest.v1.schema.json +174 -0
- package/schemas/decision/DecisionIssueTriageEvaluationReport.v1.schema.json +280 -0
- package/schemas/decision/DecisionIssueTriagePilotPack.v1.schema.json +114 -0
- package/schemas/decision/DecisionRouteReceipt.v1.schema.json +155 -0
- package/schemas/decision/DecisionRoutingPolicy.v1.schema.json +132 -0
- package/schemas/decision/DecisionRoutingShadowReport.v1.schema.json +170 -0
- package/schemas/decision/DecisionRoutingTask.v1.schema.json +49 -0
- package/schemas/decision/DecisionRuleset.schema.json +8 -2
- package/schemas/decision/DecisionRuleset.v1alpha2.schema.json +8 -2
- package/schemas/decision/DecisionSensitivityPlan.v1.schema.json +191 -0
- package/schemas/decision/DecisionSensitivityReport.v1.schema.json +163 -0
- package/schemas/decision/HeldoutApproval.v1.schema.json +312 -0
- package/schemas/decision/HeldoutAttempt.v1.schema.json +211 -0
- package/schemas/decision/HeldoutBaseline.v1.schema.json +90 -0
- package/schemas/decision/HeldoutCalibrationPhase.v1.schema.json +87 -0
- package/schemas/decision/HeldoutCorpus.v1.schema.json +167 -0
- package/schemas/decision/HeldoutEvent.v1.schema.json +41 -0
- package/schemas/decision/HeldoutFrozen.v1.schema.json +142 -0
- package/schemas/decision/HeldoutPreregistration.v1.schema.json +222 -0
- package/schemas/decision/HeldoutSpendEvent.v1.schema.json +122 -0
- package/schemas/decision/HeldoutSpendHead.v1.schema.json +25 -0
- package/schemas/decision/HeldoutSpendHead.v2.schema.json +46 -0
- package/schemas/decision/HeldoutSummary.v1.schema.json +101 -0
- package/schemas/decision/OpaDecisionLogExport.v1.schema.json +65 -0
- package/schemas/decision/PreprocessedEvidence.v1.schema.json +306 -0
- package/schemas/decision/RulesetResult.v1alpha2.schema.json +175 -0
- package/schemas/decision/SdlcEvidenceScreening.v1.schema.json +499 -0
- package/schemas/decision/SdlcScreeningPreregistration.v1.schema.json +132 -0
- package/schemas/decision/SdlcScreeningPreregistration.v2.schema.json +138 -0
- package/schemas/decision/SdlcScreeningRelease.v1.schema.json +654 -0
- package/schemas/decision/SdlcScreeningRelease.v2.schema.json +654 -0
- package/tools/agents/deploy-agents.mjs +1 -1
- package/tools/agents/providers/base.mjs +26 -7
- package/tools/agents/providers/factory.mjs +10 -2
- package/tools/agents/providers/muse-hooks.mjs +1 -29
- package/tools/agents/providers/muse.mjs +6 -3
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
import { heldoutDigest, validateHeldoutAttempt, validateHeldoutInputs } from '../heldout/contract.js';
|
|
2
|
+
import { artifactPin } from '../validate.js';
|
|
3
|
+
import { aggregateEnsembleResults } from '../ensemble/aggregate.js';
|
|
4
|
+
import { validateChampionChallenger, pairedThresholdsDigest } from '../ensemble/contract.js';
|
|
5
|
+
import { buildEnsembleIntegrityReport } from '../ensemble/report.js';
|
|
6
|
+
import { championChallengerInputSetDigest, championChallengerShadowBaseline, runChampionChallengerShadow } from '../ensemble/runtime.js';
|
|
7
|
+
import { qualificationIntegrityAllowlistProblems } from '../qualification/release.js';
|
|
8
|
+
import { evaluateBinaryHeldout, freezeQualificationSplit } from '../qualification/quality.js';
|
|
9
|
+
import { D17_ANALYSIS } from './protocol.js';
|
|
10
|
+
import { d17Statistics } from './statistics.js';
|
|
11
|
+
import { validateD17Artifact } from './artifacts.js';
|
|
12
|
+
import { applyD17Mapping, assertD17Staged, d17AttemptsByRow, d17RawProbabilities, verifyD17CalibrationSet } from './calibration.js';
|
|
13
|
+
import { calibrationIdentityDigest } from '../calibration/registry.js';
|
|
14
|
+
import { canonicalJson } from '../../security/artifact-trust.js';
|
|
15
|
+
function policy(prepared, rowAttempts) {
|
|
16
|
+
const first = rowAttempts.find(attempt => attempt.result?.receipt)?.result?.receipt;
|
|
17
|
+
if (!first)
|
|
18
|
+
return null;
|
|
19
|
+
const definition = artifactPin(prepared.corpus.definitions[0]);
|
|
20
|
+
return { schemaVersion: 'decision-ensemble-policy/v1', id: 'd17-synthetic-repeated-sample', version: '1.0.0',
|
|
21
|
+
mode: 'offline-shadow', riskTiers: ['synthetic-diagnostic'], definition, primitive: 'choice', options: ['no', 'yes'],
|
|
22
|
+
compatibleUncertaintyProfiles: ['typesafe-distribution-v1'], requiredCapabilities: ['choice', 'probability-distribution'],
|
|
23
|
+
members: [{ id: 'jev', memberType: 'repeated-sample', definition, binding: first.spec.binding,
|
|
24
|
+
adapter: { id: 'jev', version: '1.0.0' }, model: { provider: 'jev', backend: 'api', requested: 'jev-1.13.0', pinnedVersion: 'jev-1.13.0' },
|
|
25
|
+
primitive: 'choice', uncertaintyProfile: 'typesafe-distribution-v1', requiredCapabilities: ['choice', 'probability-distribution'],
|
|
26
|
+
capabilities: ['choice', 'probability-distribution'], calibration: null, samples: 3, fallbackDepth: 0,
|
|
27
|
+
estimate: { attemptsPerSample: 2, tokensPerAttempt: 4000, costMicrosPerAttempt: 400, deadlineMsPerAttempt: prepared.preregistration.requestTimeoutMs },
|
|
28
|
+
approvalReference: null }], aggregation: { algorithm: 'mean-probability-v1', tieRule: D17_ANALYSIS.acceptance.tieRule },
|
|
29
|
+
disagreement: { metric: D17_ANALYSIS.acceptance.disagreementMetric, thresholdBps: D17_ANALYSIS.acceptance.maximumDisagreementBps, onExceeded: 'defer' },
|
|
30
|
+
acceptance: { minimumSuccessfulMembers: D17_ANALYSIS.acceptance.minimumSuccessfulMembers, onInsufficientMembers: 'defer',
|
|
31
|
+
highAgreementWarningBps: D17_ANALYSIS.acceptance.highAgreementWarningBps }, calibration: { requirement: 'advisory' },
|
|
32
|
+
ceilings: { members: 1, attempts: 6, deadlineMs: prepared.preregistration.requestTimeoutMs * 6, tokens: 24000, costMicros: 2400,
|
|
33
|
+
concurrency: 1, fallbackDepth: 0, unknownCost: { rule: 'reject' } } };
|
|
34
|
+
}
|
|
35
|
+
/** Maps retained provider distributions only; confidence and agreement never become calibrated probability. */
|
|
36
|
+
export async function scoreD17Study(input, prepared) {
|
|
37
|
+
validateHeldoutInputs(input.corpus, input.preregistration);
|
|
38
|
+
if (input.preregistration.calibration.scope !== 'uncalibrated-diagnostic'
|
|
39
|
+
|| !input.approvedCalibration || input.approvedCalibration.mode !== 'uncalibrated-diagnostic'
|
|
40
|
+
|| Object.keys(input.approvedCalibration).join(',') !== 'mode' || input.calibrated !== false) {
|
|
41
|
+
throw new Error('D17 uncalibrated diagnostic scope');
|
|
42
|
+
}
|
|
43
|
+
if (heldoutDigest(input.corpus) !== heldoutDigest(prepared.corpus)
|
|
44
|
+
|| heldoutDigest(input.preregistration) !== heldoutDigest(prepared.preregistration)
|
|
45
|
+
|| heldoutDigest(input.gold) !== input.corpus.provenance.goldDigest
|
|
46
|
+
|| heldoutDigest(prepared.gold) !== input.corpus.provenance.goldDigest)
|
|
47
|
+
throw new Error('D17 frozen scoring pins');
|
|
48
|
+
const integrityProblems = qualificationIntegrityAllowlistProblems(input.integrity);
|
|
49
|
+
if (integrityProblems.includes('integrity-invalid'))
|
|
50
|
+
throw new Error('D17 invalid integrity');
|
|
51
|
+
const rows = new Map(input.corpus.rows.map(row => [row.id, row]));
|
|
52
|
+
const seen = new Set();
|
|
53
|
+
for (const attempt of input.attempts) {
|
|
54
|
+
validateHeldoutAttempt(attempt);
|
|
55
|
+
const row = rows.get(attempt.rowId), key = `${attempt.rowId}/${attempt.requestId}/${attempt.ordinal}`;
|
|
56
|
+
if (!row || !row.requests.some(request => request.id === attempt.requestId) || seen.has(key)
|
|
57
|
+
|| attempt.corpusDigest !== input.preregistration.corpusDigest || attempt.study !== 'D17'
|
|
58
|
+
|| attempt.preregistrationDigest !== heldoutDigest(input.preregistration))
|
|
59
|
+
throw new Error('D17 attempt membership');
|
|
60
|
+
seen.add(key);
|
|
61
|
+
}
|
|
62
|
+
const armAttempts = (row, candidate) => input.attempts.filter(attempt => attempt.rowId === row.id
|
|
63
|
+
&& (candidate ? attempt.requestId.startsWith('member_') : attempt.requestId === 'champion'));
|
|
64
|
+
const member = (row, requestId) => {
|
|
65
|
+
const attempts = input.attempts.filter(attempt => attempt.rowId === row.id && attempt.requestId === requestId).sort((a, b) => a.ordinal - b.ordinal);
|
|
66
|
+
const terminal = attempts.at(-1)?.result;
|
|
67
|
+
const decision = terminal?.receipt?.spec.evaluations.q0;
|
|
68
|
+
const uncertainty = decision?.spec.uncertainty;
|
|
69
|
+
const ok = terminal?.disposition === 'success' && terminal.servedModel === 'jev-1.13.0'
|
|
70
|
+
&& decision?.spec.status === 'success' && uncertainty?.source === 'provider'
|
|
71
|
+
&& uncertainty.profile === 'typesafe-distribution-v1' && uncertainty.distribution !== null;
|
|
72
|
+
if (ok && (Object.keys(uncertainty.distribution).sort().join(',') !== 'no,yes'
|
|
73
|
+
|| !['yes', 'no'].includes(String(decision.spec.value))))
|
|
74
|
+
throw new Error('D17 native distribution');
|
|
75
|
+
return { memberId: 'jev', sampleIndex: requestId === 'champion' ? 0 : Number(requestId.slice(-1)) - 1,
|
|
76
|
+
status: ok ? 'succeeded' : 'failed', resultDigest: heldoutDigest(attempts), value: ok ? decision.spec.value : null,
|
|
77
|
+
distribution: ok ? uncertainty.distribution : null, uncertaintyProfile: ok ? uncertainty.profile : null };
|
|
78
|
+
};
|
|
79
|
+
const measured = (probability, accepted, value, gold, attempts) => ({
|
|
80
|
+
probability, accepted, correct: accepted && value === gold, brier: (probability - Number(gold === 'yes')) ** 2,
|
|
81
|
+
latencyMs: attempts.reduce((sum, attempt) => sum + (attempt.result?.latencyMs ?? 0), 0),
|
|
82
|
+
tokens: attempts.some(attempt => !attempt.result || attempt.result.inputTokens === null || attempt.result.outputTokens === null) ? null
|
|
83
|
+
: attempts.reduce((sum, attempt) => sum + attempt.result.inputTokens + attempt.result.outputTokens, 0),
|
|
84
|
+
reservedCostMicros: attempts.reduce((sum, attempt) => sum + Math.max(attempt.reservedUsdMicros, attempt.result?.accountedUsdMicros ?? 0), 0),
|
|
85
|
+
});
|
|
86
|
+
const pairs = [], observations = [];
|
|
87
|
+
let championCorrect = 0, challengerCorrect = 0;
|
|
88
|
+
const test = input.corpus.rows.filter(row => row.split === 'test');
|
|
89
|
+
for (const row of test) {
|
|
90
|
+
const single = member(row, 'champion'), members = [1, 2, 3].map(n => member(row, `member_${n}`));
|
|
91
|
+
const candidateAttempts = armAttempts(row, true), championAttempts = armAttempts(row, false);
|
|
92
|
+
const ensemblePolicy = policy(prepared, candidateAttempts);
|
|
93
|
+
const aggregate = ensemblePolicy ? aggregateEnsembleResults(ensemblePolicy, members) : null;
|
|
94
|
+
const gold = prepared.gold.labels[row.id];
|
|
95
|
+
const champion = single.status === 'succeeded' ? measured(single.distribution.yes, single.distribution.yes !== single.distribution.no, single.value, gold, championAttempts) : null;
|
|
96
|
+
const challenger = members.every(m => m.status === 'succeeded') && aggregate?.statistics.meanDistribution
|
|
97
|
+
? measured(aggregate.statistics.meanDistribution.yes, aggregate.outcome.disposition === 'accept', aggregate.outcome.value, gold, candidateAttempts) : null;
|
|
98
|
+
championCorrect += Number(champion?.correct ?? false);
|
|
99
|
+
challengerCorrect += Number(challenger?.correct ?? false);
|
|
100
|
+
if (champion && challenger)
|
|
101
|
+
pairs.push({ id: row.id, slice: row.slice, champion, challenger });
|
|
102
|
+
const observation = (arm, attempts) => arm ? {
|
|
103
|
+
inputDigest: heldoutDigest(row.input), receiptDigest: heldoutDigest(attempts), quality: Number(arm.correct), calibration: arm.brier,
|
|
104
|
+
riskCoverage: Number(arm.accepted && !arm.correct), abstention: Number(!arm.accepted), latencyMs: arm.latencyMs,
|
|
105
|
+
tokens: arm.tokens, costMicros: arm.reservedCostMicros, slice: Number(arm.correct),
|
|
106
|
+
} : null;
|
|
107
|
+
observations.push({ id: row.id, champion: observation(champion, championAttempts), challenger: observation(challenger, candidateAttempts), aggregate });
|
|
108
|
+
}
|
|
109
|
+
const statistics = d17Statistics(pairs, test.map(row => row.id));
|
|
110
|
+
statistics.worstCaseFailureAsError.championCorrect = championCorrect;
|
|
111
|
+
statistics.worstCaseFailureAsError.challengerCorrect = challengerCorrect;
|
|
112
|
+
const splits = ['tuning', 'calibration', 'test'].map(split => freezeQualificationSplit(split, input.corpus.rows.filter(row => row.split === split).map(row => row.id)));
|
|
113
|
+
const binary = (role) => pairs.length === test.length ? evaluateBinaryHeldout(splits, pairs.map(pair => {
|
|
114
|
+
const attempts = armAttempts(rows.get(pair.id), role === 'challenger');
|
|
115
|
+
const known = (key) => attempts.some(a => !a.result || a.result[key] === null)
|
|
116
|
+
? null : attempts.reduce((sum, a) => sum + a.result[key], 0);
|
|
117
|
+
return { id: pair.id, slice: pair.slice, label: Number(prepared.gold.labels[pair.id] === 'yes'),
|
|
118
|
+
probability: pair[role].probability, accepted: pair[role].accepted, latencyMs: pair[role].latencyMs,
|
|
119
|
+
inputTokens: known('inputTokens'), outputTokens: known('outputTokens'), costUsd: known('providerCostUsd'),
|
|
120
|
+
calls: attempts.length, retries: attempts.filter(a => a.ordinal > 1).length, fallbacks: 0 };
|
|
121
|
+
})) : null;
|
|
122
|
+
const reservation = (attempts) => attempts.reduce((sum, attempt) => sum + Math.max(attempt.reservedUsdMicros, attempt.result?.accountedUsdMicros ?? 0), 0);
|
|
123
|
+
const definitionPin = artifactPin(input.corpus.definitions[0]);
|
|
124
|
+
const successful = input.attempts.filter(attempt => attempt.result?.disposition === 'success');
|
|
125
|
+
const bindingPin = successful[0]?.result?.receipt?.spec.binding ?? null;
|
|
126
|
+
if (successful.some(attempt => !attempt.result?.receipt
|
|
127
|
+
|| heldoutDigest(attempt.result.receipt.spec.binding) !== heldoutDigest(bindingPin)
|
|
128
|
+
|| Object.values(attempt.result.receipt.spec.evaluations).some(result => heldoutDigest(result.spec.decision) !== heldoutDigest(definitionPin)))) {
|
|
129
|
+
throw new Error('D17 mixed execution pins');
|
|
130
|
+
}
|
|
131
|
+
const testIds = new Set(test.map(row => row.id));
|
|
132
|
+
const testAttempts = input.attempts.filter(attempt => testIds.has(attempt.rowId));
|
|
133
|
+
const championReservations = reservation(testAttempts.filter(attempt => attempt.requestId === 'champion'));
|
|
134
|
+
const challengerReservations = reservation(testAttempts.filter(attempt => attempt.requestId !== 'champion'));
|
|
135
|
+
const report = { schemaVersion: 'decision-d17-study-report/v1', scope: 'synthetic-diagnostic-only',
|
|
136
|
+
calibrated: false, d09Qualified: false, calibratedGate: false,
|
|
137
|
+
corpusDigest: heldoutDigest(input.corpus), preregistrationDigest: heldoutDigest(input.preregistration),
|
|
138
|
+
executionPins: { definition: definitionPin, binding: bindingPin, model: 'jev-1.13.0', adapter: { id: 'jev', version: '1.0.0' },
|
|
139
|
+
aggregatePolicyDigest: observations.find(row => row.aggregate)?.aggregate?.policy.digest ?? null },
|
|
140
|
+
integrityDigest: heldoutDigest(input.integrity), integrity: structuredClone(input.integrity), integrityProblems,
|
|
141
|
+
statistics, statisticsDigest: heldoutDigest(statistics), pairs, observations,
|
|
142
|
+
accounting: { allSplits: { attempts: input.attempts.length, reservedCostMicros: reservation(input.attempts) },
|
|
143
|
+
test: { championReservedCostMicros: championReservations, challengerReservedCostMicros: challengerReservations,
|
|
144
|
+
netSavingsMicros: championReservations - challengerReservations, complete: pairs.length === test.length } },
|
|
145
|
+
calibrationDiagnostics: { champion: binary('champion'), challenger: binary('challenger'), calibrated: false },
|
|
146
|
+
pending: ['D09 compatible member and aggregate calibration', 'blind gold audit and delayed repeats', 'separate extra-cost tradeoff approval',
|
|
147
|
+
'protected native report approval and eligibility'],
|
|
148
|
+
decision: input.integrity.release_gate.decision === 'ROLLBACK' || input.integrity.compromise_labels.length ? 'ROLLBACK' : 'HOLD' };
|
|
149
|
+
validateD17Artifact('report', report);
|
|
150
|
+
return report;
|
|
151
|
+
}
|
|
152
|
+
/** Native serialization requires a separately anchored record. It cannot create approval or eligibility. */
|
|
153
|
+
export async function buildD17NativeReport(input) {
|
|
154
|
+
const staged = input.report.schemaVersion === 'decision-d17-study-report/v2';
|
|
155
|
+
validateD17Artifact(staged ? 'reportV2' : 'report', input.report);
|
|
156
|
+
if (!staged && (input.eligibility !== undefined || input.tradeoff !== undefined))
|
|
157
|
+
throw new Error('D17 diagnostic native report has no promotion route');
|
|
158
|
+
if (input.eligibility !== undefined) {
|
|
159
|
+
const stored = input.registry?.promotionEligibility(input.record.eligibilityId) ?? null;
|
|
160
|
+
if (!stored || canonicalJson(stored) !== canonicalJson(input.eligibility))
|
|
161
|
+
throw new Error('D17 native eligibility');
|
|
162
|
+
}
|
|
163
|
+
if (staged) {
|
|
164
|
+
// AC7/AC14: each role must cite the exact D09 artifact the calibrated report applied to it.
|
|
165
|
+
const calibration = input.report.calibration, record = input.record;
|
|
166
|
+
const cites = (role, pin) => record[role]?.calibration?.artifactId === pin.artifactId && record[role]?.calibration?.artifactDigest === pin.artifactDigest;
|
|
167
|
+
assertD17Staged(input.prepared);
|
|
168
|
+
if (!cites('champion', calibration.member) || !cites('challenger', calibration.aggregate))
|
|
169
|
+
throw new Error('D17 native calibration pins');
|
|
170
|
+
}
|
|
171
|
+
const { record } = validateChampionChallenger(input.record);
|
|
172
|
+
const problems = qualificationIntegrityAllowlistProblems(input.integrity);
|
|
173
|
+
if (problems.includes('integrity-invalid') || heldoutDigest(input.integrity) !== input.trustedIntegrityDigest
|
|
174
|
+
|| record.evaluationIntegrityReport.digest !== input.trustedIntegrityDigest)
|
|
175
|
+
throw new Error('D17 native integrity pin');
|
|
176
|
+
if (heldoutDigest(input.report) !== input.trustedReportDigest || input.report.integrityDigest !== heldoutDigest(input.report.integrity)
|
|
177
|
+
|| input.report.corpusDigest !== heldoutDigest(input.prepared.corpus)
|
|
178
|
+
|| input.report.preregistrationDigest !== heldoutDigest(input.prepared.preregistration)
|
|
179
|
+
|| input.report.statisticsDigest !== heldoutDigest(input.report.statistics)
|
|
180
|
+
|| record.preregistration.thresholdsDigest !== pairedThresholdsDigest([...D17_ANALYSIS.native])
|
|
181
|
+
|| input.integrity.release_gate.decision === 'PROMOTE'
|
|
182
|
+
&& (!staged || !d17PromotionSupported(input.report, input.integrity, input.tradeoff, input.trustedTradeoffDigest))
|
|
183
|
+
|| input.report.decision === 'ROLLBACK' && input.integrity.release_gate.decision !== 'ROLLBACK')
|
|
184
|
+
throw new Error('D17 native report needs anchored HOLD or ROLLBACK');
|
|
185
|
+
const pins = input.report.executionPins;
|
|
186
|
+
if (!pins.binding || !pins.aggregatePolicyDigest || record.champion.ensemblePolicy !== null
|
|
187
|
+
|| record.challenger.ensemblePolicy?.digest !== pins.aggregatePolicyDigest
|
|
188
|
+
|| [record.champion, record.challenger].some(role => role.actualModel !== pins.model
|
|
189
|
+
|| heldoutDigest(role.binding) !== heldoutDigest(pins.binding) || heldoutDigest(role.adapter) !== heldoutDigest(pins.adapter))) {
|
|
190
|
+
throw new Error('D17 native execution pins');
|
|
191
|
+
}
|
|
192
|
+
const items = input.prepared.corpus.rows.filter(row => row.split === 'test').map(row => ({ id: row.id, input: row.input, slice: row.slice }));
|
|
193
|
+
if (record.inputSet.digest !== championChallengerInputSetDigest(items))
|
|
194
|
+
throw new Error('D17 native membership');
|
|
195
|
+
const shadow = await runChampionChallengerShadow(record, { enabled: true, invocationId: 'd17-recorded-replay', items,
|
|
196
|
+
evaluate: async ({ role, item }) => {
|
|
197
|
+
const observation = input.report.observations.find(row => row.id === item.id)?.[role];
|
|
198
|
+
if (!observation || observation.tokens === null)
|
|
199
|
+
throw new Error('D17 incomplete native endpoints');
|
|
200
|
+
return observation;
|
|
201
|
+
} });
|
|
202
|
+
const baseline = championChallengerShadowBaseline(record, shadow);
|
|
203
|
+
const upstream = input.integrity.paired_baseline;
|
|
204
|
+
if (!upstream || heldoutDigest(upstream.championChallengerShadow ?? null) !== heldoutDigest(baseline)
|
|
205
|
+
|| upstream.d17StatisticsDigest !== input.report.statisticsDigest)
|
|
206
|
+
throw new Error('D17 unbound native statistics');
|
|
207
|
+
return buildEnsembleIntegrityReport({ record, integrity: input.integrity, pairedDeltas: shadow.pairedDeltas, eligibility: input.eligibility ?? null });
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Calibrated test-phase scorer (#2611 staged D09). The collector passes only test rows and `calibrated: null`.
|
|
211
|
+
* The approved calibration set, both approved artifacts, their mappings and the completed development review
|
|
212
|
+
* are verified and D09-qualified at the scoring clock before any row is scored. The champion's native P(yes)
|
|
213
|
+
* passes through the member calibrator; the challenger's raw three-member mean passes through the aggregate
|
|
214
|
+
* calibrator, and it is accepted only when the native aggregate accepts and the calibrated value is not a tie.
|
|
215
|
+
* The frozen D17 native gates are evaluated on those calibrated measurements; the uncalibrated statistics are
|
|
216
|
+
* retained as a descriptive comparison. The decision is HOLD or a preserved ROLLBACK, never PROMOTE.
|
|
217
|
+
*/
|
|
218
|
+
export async function scoreD17StagedStudy(input, prepared, context) {
|
|
219
|
+
assertD17Staged(prepared);
|
|
220
|
+
if (input.preregistration?.calibration?.scope !== 'calibrated' || input.calibrated !== null)
|
|
221
|
+
throw new Error('D17 staged calibration scope');
|
|
222
|
+
const testRows = prepared.corpus.rows.filter(row => row.split === 'test');
|
|
223
|
+
if (heldoutDigest(input.corpus) !== heldoutDigest({ ...prepared.corpus, rows: testRows })
|
|
224
|
+
|| heldoutDigest(input.preregistration) !== heldoutDigest(prepared.preregistration)
|
|
225
|
+
|| heldoutDigest(input.gold) !== prepared.corpus.provenance.goldDigest
|
|
226
|
+
|| heldoutDigest(prepared.gold) !== prepared.corpus.provenance.goldDigest)
|
|
227
|
+
throw new Error('D17 frozen scoring pins');
|
|
228
|
+
if (!context || typeof context.testPhaseAccessAt !== 'string')
|
|
229
|
+
throw new Error('D17 staged test access');
|
|
230
|
+
const verified = verifyD17CalibrationSet(prepared, input.approvedCalibration, context);
|
|
231
|
+
const integrityProblems = qualificationIntegrityAllowlistProblems(input.integrity);
|
|
232
|
+
if (integrityProblems.includes('integrity-invalid'))
|
|
233
|
+
throw new Error('D17 invalid integrity');
|
|
234
|
+
const rows = new Map(testRows.map(row => [row.id, row]));
|
|
235
|
+
const seen = new Set();
|
|
236
|
+
for (const attempt of input.attempts) {
|
|
237
|
+
validateHeldoutAttempt(attempt);
|
|
238
|
+
const row = rows.get(attempt.rowId), key = `${attempt.rowId}/${attempt.requestId}/${attempt.ordinal}`;
|
|
239
|
+
if (!row || !row.requests.some(request => request.id === attempt.requestId) || seen.has(key)
|
|
240
|
+
|| attempt.corpusDigest !== input.preregistration.corpusDigest || attempt.study !== 'D17'
|
|
241
|
+
|| attempt.preregistrationDigest !== heldoutDigest(input.preregistration))
|
|
242
|
+
throw new Error('D17 attempt membership');
|
|
243
|
+
seen.add(key);
|
|
244
|
+
}
|
|
245
|
+
const grouped = d17AttemptsByRow(input.attempts), rowAttempts = (row) => grouped.get(row.id) ?? [];
|
|
246
|
+
const of = (row, candidate) => rowAttempts(row).filter(attempt => candidate ? attempt.requestId.startsWith('member_') : attempt.requestId === 'champion');
|
|
247
|
+
const member = (row, requestId) => {
|
|
248
|
+
const attempts = rowAttempts(row).filter(attempt => attempt.requestId === requestId).sort((a, b) => a.ordinal - b.ordinal);
|
|
249
|
+
const terminal = attempts.at(-1)?.result, decision = terminal?.receipt?.spec.evaluations.q0, uncertainty = decision?.spec.uncertainty;
|
|
250
|
+
const ok = terminal?.disposition === 'success' && terminal.servedModel === 'jev-1.13.0' && decision?.spec.status === 'success'
|
|
251
|
+
&& uncertainty?.source === 'provider' && uncertainty.profile === 'typesafe-distribution-v1' && uncertainty.distribution !== null;
|
|
252
|
+
if (ok && (Object.keys(uncertainty.distribution).sort().join(',') !== 'no,yes' || !['yes', 'no'].includes(String(decision.spec.value))))
|
|
253
|
+
throw new Error('D17 native distribution');
|
|
254
|
+
return { memberId: 'jev', sampleIndex: requestId === 'champion' ? 0 : Number(requestId.slice(-1)) - 1,
|
|
255
|
+
status: ok ? 'succeeded' : 'failed', resultDigest: heldoutDigest(attempts), value: ok ? decision.spec.value : null,
|
|
256
|
+
distribution: ok ? uncertainty.distribution : null, uncertaintyProfile: ok ? uncertainty.profile : null };
|
|
257
|
+
};
|
|
258
|
+
const arm = (probability, accepted, value, gold, attempts) => ({
|
|
259
|
+
probability, accepted, correct: accepted && value === gold, brier: (probability - Number(gold === 'yes')) ** 2,
|
|
260
|
+
latencyMs: attempts.reduce((sum, attempt) => sum + (attempt.result?.latencyMs ?? 0), 0),
|
|
261
|
+
tokens: attempts.some(attempt => !attempt.result || attempt.result.inputTokens === null || attempt.result.outputTokens === null) ? null
|
|
262
|
+
: attempts.reduce((sum, attempt) => sum + attempt.result.inputTokens + attempt.result.outputTokens, 0),
|
|
263
|
+
reservedCostMicros: attempts.reduce((sum, attempt) => sum + Math.max(attempt.reservedUsdMicros, attempt.result?.accountedUsdMicros ?? 0), 0),
|
|
264
|
+
});
|
|
265
|
+
const calibratedValue = (p) => p > 0.5 ? 'yes' : p < 0.5 ? 'no' : null;
|
|
266
|
+
const pairs = [], rawPairs = [], observations = [];
|
|
267
|
+
let championCorrect = 0, challengerCorrect = 0;
|
|
268
|
+
for (const row of testRows) {
|
|
269
|
+
const single = member(row, 'champion'), members = [1, 2, 3].map(n => member(row, `member_${n}`));
|
|
270
|
+
const candidateAttempts = of(row, true), championAttempts = of(row, false);
|
|
271
|
+
const ensemblePolicy = policy(prepared, candidateAttempts);
|
|
272
|
+
const aggregate = ensemblePolicy ? aggregateEnsembleResults(ensemblePolicy, members) : null;
|
|
273
|
+
const gold = prepared.gold.labels[row.id], raw = d17RawProbabilities(rowAttempts(row), row);
|
|
274
|
+
let champion = null, challenger = null;
|
|
275
|
+
if (single.status === 'succeeded' && raw.champion !== null) {
|
|
276
|
+
const p = applyD17Mapping(verified.member.mapping, raw.champion);
|
|
277
|
+
champion = arm(p, calibratedValue(p) !== null, calibratedValue(p), gold, championAttempts);
|
|
278
|
+
}
|
|
279
|
+
if (members.every(m => m.status === 'succeeded') && aggregate?.statistics.meanDistribution && raw.mean !== null) {
|
|
280
|
+
const p = applyD17Mapping(verified.aggregate.mapping, raw.mean);
|
|
281
|
+
challenger = arm(p, aggregate.outcome.disposition === 'accept' && calibratedValue(p) !== null, calibratedValue(p), gold, candidateAttempts);
|
|
282
|
+
}
|
|
283
|
+
// Uncalibrated comparison: the original v1 measurements, descriptive only.
|
|
284
|
+
const rawChampion = single.status === 'succeeded' ? arm(single.distribution.yes, single.distribution.yes !== single.distribution.no, single.value, gold, championAttempts) : null;
|
|
285
|
+
const rawChallenger = members.every(m => m.status === 'succeeded') && aggregate?.statistics.meanDistribution ? arm(aggregate.statistics.meanDistribution.yes, aggregate.outcome.disposition === 'accept', aggregate.outcome.value, gold, candidateAttempts) : null;
|
|
286
|
+
if (rawChampion && rawChallenger)
|
|
287
|
+
rawPairs.push({ id: row.id, slice: row.slice, champion: rawChampion, challenger: rawChallenger });
|
|
288
|
+
championCorrect += Number(champion?.correct ?? false);
|
|
289
|
+
challengerCorrect += Number(challenger?.correct ?? false);
|
|
290
|
+
if (champion && challenger)
|
|
291
|
+
pairs.push({ id: row.id, slice: row.slice, champion, challenger });
|
|
292
|
+
const observation = (measured, attempts) => measured ? {
|
|
293
|
+
inputDigest: heldoutDigest(row.input), receiptDigest: heldoutDigest(attempts), quality: Number(measured.correct), calibration: measured.brier,
|
|
294
|
+
riskCoverage: Number(measured.accepted && !measured.correct), abstention: Number(!measured.accepted), latencyMs: measured.latencyMs,
|
|
295
|
+
tokens: measured.tokens, costMicros: measured.reservedCostMicros, slice: Number(measured.correct),
|
|
296
|
+
} : null;
|
|
297
|
+
observations.push({ id: row.id, champion: observation(champion, championAttempts), challenger: observation(challenger, candidateAttempts), aggregate });
|
|
298
|
+
}
|
|
299
|
+
const ids = testRows.map(row => row.id);
|
|
300
|
+
const statistics = d17Statistics(pairs, ids);
|
|
301
|
+
statistics.worstCaseFailureAsError.championCorrect = championCorrect;
|
|
302
|
+
statistics.worstCaseFailureAsError.challengerCorrect = challengerCorrect;
|
|
303
|
+
const uncalibratedStatistics = d17Statistics(rawPairs, ids);
|
|
304
|
+
const splits = ['tuning', 'calibration', 'test'].map(split => freezeQualificationSplit(split, prepared.corpus.rows.filter(row => row.split === split).map(row => row.id)));
|
|
305
|
+
const binary = (role) => pairs.length === testRows.length ? evaluateBinaryHeldout(splits, pairs.map(pair => {
|
|
306
|
+
const attempts = of(rows.get(pair.id), role === 'challenger');
|
|
307
|
+
const known = (key) => attempts.some(a => !a.result || a.result[key] === null)
|
|
308
|
+
? null : attempts.reduce((sum, a) => sum + a.result[key], 0);
|
|
309
|
+
return { id: pair.id, slice: pair.slice, label: Number(prepared.gold.labels[pair.id] === 'yes'),
|
|
310
|
+
probability: pair[role].probability, accepted: pair[role].accepted, latencyMs: pair[role].latencyMs,
|
|
311
|
+
inputTokens: known('inputTokens'), outputTokens: known('outputTokens'), costUsd: known('providerCostUsd'),
|
|
312
|
+
calls: attempts.length, retries: attempts.filter(a => a.ordinal > 1).length, fallbacks: 0 };
|
|
313
|
+
})) : null;
|
|
314
|
+
const reservation = (attempts) => attempts.reduce((sum, attempt) => sum + Math.max(attempt.reservedUsdMicros, attempt.result?.accountedUsdMicros ?? 0), 0);
|
|
315
|
+
const definitionPin = artifactPin(prepared.corpus.definitions[0]);
|
|
316
|
+
const successful = input.attempts.filter(attempt => attempt.result?.disposition === 'success');
|
|
317
|
+
const bindingPin = successful[0]?.result?.receipt?.spec.binding ?? null;
|
|
318
|
+
if (successful.some(attempt => !attempt.result?.receipt || heldoutDigest(attempt.result.receipt.spec.binding) !== heldoutDigest(bindingPin)
|
|
319
|
+
|| Object.values(attempt.result.receipt.spec.evaluations).some(result => heldoutDigest(result.spec.decision) !== heldoutDigest(definitionPin)))) {
|
|
320
|
+
throw new Error('D17 mixed execution pins');
|
|
321
|
+
}
|
|
322
|
+
const championReservations = reservation(input.attempts.filter(attempt => attempt.requestId === 'champion'));
|
|
323
|
+
const challengerReservations = reservation(input.attempts.filter(attempt => attempt.requestId !== 'champion'));
|
|
324
|
+
const pin = (role) => ({ artifactId: verified[role].artifact.id, artifactDigest: verified[role].artifact.digest,
|
|
325
|
+
mappingDigest: heldoutDigest(verified[role].mapping), compatibility: { action: 'allow',
|
|
326
|
+
state: verified[role].compatibility.state, pinId: verified[role].compatibility.pinId } });
|
|
327
|
+
const approved = input.approvedCalibration;
|
|
328
|
+
const decision = input.integrity.release_gate.decision === 'ROLLBACK' || input.integrity.compromise_labels.length ? 'ROLLBACK' : 'HOLD';
|
|
329
|
+
const report = { schemaVersion: 'decision-d17-study-report/v2', scope: 'synthetic-staged-calibrated',
|
|
330
|
+
calibrated: true, d09Qualified: true, calibratedGate: true,
|
|
331
|
+
corpusDigest: heldoutDigest(prepared.corpus), preregistrationDigest: heldoutDigest(prepared.preregistration),
|
|
332
|
+
executionPins: { definition: definitionPin, binding: bindingPin, model: 'jev-1.13.0', adapter: { id: 'jev', version: '1.0.0' },
|
|
333
|
+
aggregatePolicyDigest: observations.find(row => row.aggregate)?.aggregate?.policy.digest ?? null },
|
|
334
|
+
integrityDigest: heldoutDigest(input.integrity), integrity: structuredClone(input.integrity), integrityProblems,
|
|
335
|
+
calibration: { mode: 'staged-test', calibrationSetDigest: verified.setDigest,
|
|
336
|
+
calibrationPhaseRecordDigest: approved.calibrationPhaseRecordDigest, priorApprovalDigest: approved.priorApprovalDigest,
|
|
337
|
+
member: pin('member'), aggregate: pin('aggregate'), qualifiedAt: verified.qualifiedAt,
|
|
338
|
+
applied: { champion: 'member', challenger: 'aggregate' } },
|
|
339
|
+
developmentReviewDigest: verified.developmentReviewDigest, calibrationReviewDigest: verified.calibrationReviewDigest,
|
|
340
|
+
statistics, statisticsDigest: heldoutDigest(statistics), uncalibratedStatistics, pairs, observations,
|
|
341
|
+
accounting: { allSplits: { attempts: input.attempts.length, reservedCostMicros: reservation(input.attempts) },
|
|
342
|
+
test: { championReservedCostMicros: championReservations, challengerReservedCostMicros: challengerReservations,
|
|
343
|
+
netSavingsMicros: championReservations - challengerReservations, complete: pairs.length === testRows.length } },
|
|
344
|
+
calibrationDiagnostics: { champion: binary('champion'), challenger: binary('challenger'), calibrated: true },
|
|
345
|
+
gates: { source: 'd17-native-protocol', gateBinding: null, statisticalGate: statistics.statisticalGate,
|
|
346
|
+
findings: [...statistics.findings], promotion: 'not-authorized: requires separate extra-cost tradeoff approval and D09 promotion eligibility' },
|
|
347
|
+
pending: ['blind gold audit and delayed repeats', 'separate extra-cost tradeoff approval', 'D09 promotion eligibility',
|
|
348
|
+
'protected native report approval'],
|
|
349
|
+
decision };
|
|
350
|
+
validateD17Artifact('reportV2', report);
|
|
351
|
+
return report;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Builds the real champion/challenger record and the shadow baseline for a calibrated v2 report. Each role
|
|
355
|
+
* cites the D09 artifact applied to it; identities are the calibrated decision identities. The caller binds
|
|
356
|
+
* the returned baseline and statistics digest into eval-integrity metadata, anchors that digest externally,
|
|
357
|
+
* and only then serializes the native report with `buildD17NativeReport`.
|
|
358
|
+
*/
|
|
359
|
+
export async function d17NativeHandoff(input) {
|
|
360
|
+
validateD17Artifact('reportV2', input.report);
|
|
361
|
+
assertD17Staged(input.prepared);
|
|
362
|
+
const { report, operator, artifacts } = input;
|
|
363
|
+
if (heldoutDigest(report) !== input.trustedReportDigest || report.corpusDigest !== heldoutDigest(input.prepared.corpus)
|
|
364
|
+
|| report.preregistrationDigest !== heldoutDigest(input.prepared.preregistration))
|
|
365
|
+
throw new Error('D17 native report pin');
|
|
366
|
+
for (const role of ['member', 'aggregate']) {
|
|
367
|
+
if (artifacts[role].id !== report.calibration[role].artifactId || artifacts[role].digest !== report.calibration[role].artifactDigest) {
|
|
368
|
+
throw new Error('D17 native calibration pins');
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
const pins = report.executionPins;
|
|
372
|
+
if (!pins.binding || !pins.aggregatePolicyDigest || !report.accounting.test.complete)
|
|
373
|
+
throw new Error('D17 incomplete native endpoints');
|
|
374
|
+
const policyPin = report.observations.find(row => row.aggregate)?.aggregate?.policy;
|
|
375
|
+
if (!policyPin || policyPin.digest !== pins.aggregatePolicyDigest)
|
|
376
|
+
throw new Error('D17 native execution pins');
|
|
377
|
+
const template = input.prepared.nativeTemplates.comparison;
|
|
378
|
+
const items = input.prepared.corpus.rows.filter(row => row.split === 'test').map(row => ({ id: row.id, input: row.input, slice: row.slice }));
|
|
379
|
+
const championIdentity = calibrationIdentityDigest(artifacts.member.identity);
|
|
380
|
+
const role = (calibration, identityDigest) => ({ identityDigest, actualModel: pins.model,
|
|
381
|
+
binding: structuredClone(pins.binding), adapter: structuredClone(pins.adapter),
|
|
382
|
+
calibration: { artifactId: calibration.id, artifactDigest: calibration.digest } });
|
|
383
|
+
const record = { ...structuredClone(template), alias: operator.alias,
|
|
384
|
+
champion: { ...role(artifacts.member, championIdentity), aliasRevision: operator.aliasRevision, ensemblePolicy: null },
|
|
385
|
+
challenger: { ...role(artifacts.aggregate, calibrationIdentityDigest(artifacts.aggregate.identity)), ensemblePolicy: structuredClone(policyPin) },
|
|
386
|
+
inputSet: { ...structuredClone(template.inputSet), digest: championChallengerInputSetDigest(items) },
|
|
387
|
+
preregistration: { ...structuredClone(template.preregistration), thresholdsDigest: pairedThresholdsDigest([...D17_ANALYSIS.native]),
|
|
388
|
+
holdoutAccessedAt: operator.holdoutAccessedAt },
|
|
389
|
+
eligibilityId: operator.eligibilityId, evaluationIntegrityReport: { id: operator.integrityReportId, digest: report.integrityDigest },
|
|
390
|
+
approval: { reference: operator.approvalReference, approvedAt: operator.approvedAt },
|
|
391
|
+
rollbackTarget: { aliasRevision: operator.aliasRevision, identityDigest: championIdentity } };
|
|
392
|
+
validateChampionChallenger(record);
|
|
393
|
+
const shadow = await runChampionChallengerShadow(record, { enabled: true, invocationId: 'd17-recorded-replay', items,
|
|
394
|
+
evaluate: async ({ role: side, item }) => {
|
|
395
|
+
const observation = report.observations.find(row => row.id === item.id)?.[side];
|
|
396
|
+
if (!observation || observation.tokens === null)
|
|
397
|
+
throw new Error('D17 incomplete native endpoints');
|
|
398
|
+
return observation;
|
|
399
|
+
} });
|
|
400
|
+
return { record, pairedBaseline: { championChallengerShadow: championChallengerShadowBaseline(record, shadow),
|
|
401
|
+
d17StatisticsDigest: report.statisticsDigest } };
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* The preregistered extra-cost tradeoff: an anchored approval of this exact report and statistics that accepts at least the
|
|
405
|
+
* measured additional reservation cost and records the observed quality lower bound. It approves cost, not quality.
|
|
406
|
+
*/
|
|
407
|
+
export function validateD17Tradeoff(report, tradeoff, trustedDigest) {
|
|
408
|
+
try {
|
|
409
|
+
validateD17Artifact('calibration', tradeoff);
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
throw new Error('D17 tradeoff approval');
|
|
413
|
+
}
|
|
414
|
+
const value = tradeoff;
|
|
415
|
+
if (value.schemaVersion !== 'decision-d17-tradeoff-approval/v1' || typeof trustedDigest !== 'string' || heldoutDigest(value) !== trustedDigest
|
|
416
|
+
|| value.reportDigest !== heldoutDigest(report) || value.statisticsDigest !== report.statisticsDigest
|
|
417
|
+
|| value.netSavingsMicros !== report.statistics.netSavingsMicros || value.acceptedAdditionalCostMicros < Math.max(0, -report.statistics.netSavingsMicros)
|
|
418
|
+
|| value.qualityLowerBps !== report.statistics.quality?.lowerBps)
|
|
419
|
+
throw new Error('D17 tradeoff approval');
|
|
420
|
+
return value;
|
|
421
|
+
}
|
|
422
|
+
/** A calibrated report supports PROMOTE only with a passing study gate, a positive quality bound and the bound tradeoff. */
|
|
423
|
+
function d17PromotionSupported(report, integrity, tradeoff, trustedDigest) {
|
|
424
|
+
if (report.gates.statisticalGate !== 'pass' || !report.statistics.benefitSupported)
|
|
425
|
+
return false;
|
|
426
|
+
try {
|
|
427
|
+
validateD17Tradeoff(report, tradeoff, trustedDigest);
|
|
428
|
+
}
|
|
429
|
+
catch {
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
const upstream = integrity.paired_baseline;
|
|
433
|
+
return upstream?.d17TradeoffApprovalDigest === trustedDigest;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Eval-integrity metadata for the native D17 record. The release gate comes from the locked-snapshot evidence (`base`); a
|
|
437
|
+
* PROMOTE gate survives only when the calibrated study gate passes, the quality lower bound is positive and an anchored
|
|
438
|
+
* extra-cost tradeoff approval binds this report. Otherwise PROMOTE is held, with the missing pieces as reasons.
|
|
439
|
+
*/
|
|
440
|
+
export function d17NativeIntegrity(input) {
|
|
441
|
+
const missing = [];
|
|
442
|
+
if (input.report.gates.statisticalGate !== 'pass')
|
|
443
|
+
missing.push('D17 statistical gate did not pass');
|
|
444
|
+
if (!input.report.statistics.benefitSupported)
|
|
445
|
+
missing.push('D17 quality lower bound is not positive');
|
|
446
|
+
let tradeoffDigest = null;
|
|
447
|
+
if (input.tradeoff === undefined || input.tradeoff === null)
|
|
448
|
+
missing.push('no anchored extra-cost tradeoff approval');
|
|
449
|
+
else {
|
|
450
|
+
validateD17Tradeoff(input.report, input.tradeoff, input.trustedTradeoffDigest);
|
|
451
|
+
tradeoffDigest = input.trustedTradeoffDigest;
|
|
452
|
+
}
|
|
453
|
+
// The ensemble integrity contract carries only the gate decision and reasons (eval-tool thresholds are dropped).
|
|
454
|
+
const gate = { decision: input.base.release_gate.decision, reasons: [...input.base.release_gate.reasons] };
|
|
455
|
+
const release_gate = gate.decision === 'PROMOTE' && missing.length
|
|
456
|
+
? { decision: 'HOLD', reasons: [...gate.reasons, ...missing.map(reason => `promotion withheld: ${reason}`)] } : gate;
|
|
457
|
+
const { sample_n, uncertainty, integrity_mode, fresh_workspace_required, fresh_workspace_verified, integrity_state, trusted_score_source, compromise_labels, weak_signal_reason } = input.base;
|
|
458
|
+
return { sample_n, uncertainty, paired_baseline: { ...input.pairedBaseline, d17TradeoffApprovalDigest: tradeoffDigest },
|
|
459
|
+
integrity_mode, fresh_workspace_required, fresh_workspace_verified, integrity_state, trusted_score_source,
|
|
460
|
+
compromise_labels: [...compromise_labels], weak_signal_reason, release_gate };
|
|
461
|
+
}
|
|
462
|
+
//# sourceMappingURL=score.js.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { heldoutDigest, heldoutRequestSize, heldoutReservationMicros, heldoutReservationTokens, validateHeldoutInputs } from '../heldout/contract.js';
|
|
2
|
+
import { heldoutCollectionAllowance } from '../heldout/journal.js';
|
|
3
|
+
import { d17DryRun, prepareD17Study } from './corpus.js';
|
|
4
|
+
import { D17_ANALYSIS, D17_CALIBRATION } from './protocol.js';
|
|
5
|
+
import { validateD17Artifact } from './artifacts.js';
|
|
6
|
+
/**
|
|
7
|
+
* Staged D09 calibration preparation (#2611). The corpus, gold, split manifest, review template and native
|
|
8
|
+
* templates are exactly the diagnostic ones for the same seed (the corpus module, and therefore the corpus
|
|
9
|
+
* pin, is unchanged); only the preregistration, the v2 analysis, the calibration-phase approval form and the
|
|
10
|
+
* per-phase dry run differ. The v1 diagnostic preparation remains available and unchanged.
|
|
11
|
+
*/
|
|
12
|
+
export function prepareD17StagedStudy(seed, moduleDigest, sourceDigests) {
|
|
13
|
+
const base = prepareD17Study(seed, moduleDigest, sourceDigests);
|
|
14
|
+
const analysis = { schemaVersion: 'decision-d17-analysis/v2', protocol: D17_ANALYSIS, scope: 'staged-calibrated',
|
|
15
|
+
calibration: D17_CALIBRATION, sourceDigests: base.analysis.sourceDigests, splitManifestDigest: base.analysis.splitManifestDigest,
|
|
16
|
+
nativeTemplatesDigest: base.analysis.nativeTemplatesDigest };
|
|
17
|
+
validateD17Artifact('analysisV2', analysis);
|
|
18
|
+
const preregistration = { ...base.preregistration, studyAnalysisDigest: heldoutDigest(analysis),
|
|
19
|
+
calibration: { scope: 'calibrated', allowedModes: ['staged'], calibrationPhaseSplits: [...D17_CALIBRATION.phaseSplits] } };
|
|
20
|
+
validateHeldoutInputs(base.corpus, preregistration);
|
|
21
|
+
// The study starts with the calibration-phase approval; the test-phase form comes from the reviewed calibration set.
|
|
22
|
+
// Operator-authorized staged budget: 24,000 calls and 96M tokens give a 19,200-call allowance at the 80% stop, 4,800 calls
|
|
23
|
+
// of headroom over the 14,400-call two-phase worst case. The USD 8 study cap is unchanged.
|
|
24
|
+
const approvalTemplate = { ...base.approvalTemplate, preregistrationDigest: heldoutDigest(preregistration),
|
|
25
|
+
budget: { ...D17_STAGED_BUDGET }, calibration: { mode: 'staged', phase: 'calibration' } };
|
|
26
|
+
const dryRun = d17StagedDryRun();
|
|
27
|
+
validateD17Artifact('dryRunV2', dryRun);
|
|
28
|
+
return { ...base, preregistration, analysis, approvalTemplate, dryRun };
|
|
29
|
+
}
|
|
30
|
+
export const D17_STAGED_BUDGET = Object.freeze({ calls: 24000, tokens: 96000000, usd: 8 });
|
|
31
|
+
/** Staged planning bounds: the same 7,200 first attempts, split into the calibration and test phases. */
|
|
32
|
+
export function d17StagedDryRun() {
|
|
33
|
+
return { ...d17DryRun(), schemaVersion: 'decision-d17-dry-run/v2', approvalCeilings: { ...D17_STAGED_BUDGET },
|
|
34
|
+
phases: { calibration: { splits: ['tuning', 'calibration'], rows: 600, firstAttempts: 2400, worstCaseAttempts: 4800 },
|
|
35
|
+
test: { splits: ['test'], rows: 1200, firstAttempts: 4800, worstCaseAttempts: 9600 } },
|
|
36
|
+
missingInputs: ['completed 40-item development review', 'calibration-phase operator approval', 'exact-source CI evidence',
|
|
37
|
+
'provider terms', 'prior study and portfolio spend', 'region and credential resolver pin', 'calibration-phase live observations',
|
|
38
|
+
'fitted and operator-reviewed D09 calibration set', 'test-phase operator approval', 'test-phase live observations', 'blind human review'] };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Worst-case reservations for both staged phases from the actual projected request bytes and the approval's price bound,
|
|
42
|
+
* with every preregistered retry. The collector plans one phase at a time; this bounds the whole study before any spend.
|
|
43
|
+
*/
|
|
44
|
+
export async function d17TwoPhasePlan(corpus, preregistration, approval) {
|
|
45
|
+
const sizing = { ...approval, calibration: { mode: 'uncalibrated-diagnostic' } };
|
|
46
|
+
const attemptsPerRequest = 1 + preregistration.providerFailurePolicy.maxRetries;
|
|
47
|
+
const phase = async (splits) => {
|
|
48
|
+
const plan = { rows: 0, firstAttempts: 0, maximumAttempts: 0, maximumRequestEstimateTokens: 0, reservedTokens: 0, reservedUsdMicros: 0 };
|
|
49
|
+
for (const row of corpus.rows.filter(item => splits.includes(item.split))) {
|
|
50
|
+
plan.rows++;
|
|
51
|
+
for (const request of row.requests) {
|
|
52
|
+
const { estimatedTokens } = await heldoutRequestSize(corpus, preregistration, sizing, row, request);
|
|
53
|
+
plan.firstAttempts++;
|
|
54
|
+
plan.maximumAttempts += attemptsPerRequest;
|
|
55
|
+
plan.maximumRequestEstimateTokens = Math.max(plan.maximumRequestEstimateTokens, estimatedTokens);
|
|
56
|
+
plan.reservedTokens += attemptsPerRequest * heldoutReservationTokens(preregistration, estimatedTokens);
|
|
57
|
+
plan.reservedUsdMicros += attemptsPerRequest * heldoutReservationMicros(sizing, estimatedTokens);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return plan;
|
|
61
|
+
};
|
|
62
|
+
const calibration = await phase(D17_CALIBRATION.phaseSplits), test = await phase(['test']);
|
|
63
|
+
return { calibration, test, combined: { maximumAttempts: calibration.maximumAttempts + test.maximumAttempts,
|
|
64
|
+
reservedTokens: calibration.reservedTokens + test.reservedTokens, reservedUsdMicros: calibration.reservedUsdMicros + test.reservedUsdMicros } };
|
|
65
|
+
}
|
|
66
|
+
/** Both phases must fit the remaining collector allowance (the 80% stop thresholds net of prior charges). */
|
|
67
|
+
export function d17TwoPhaseFit(plan, allowance) {
|
|
68
|
+
const headroom = { calls: allowance.calls - plan.combined.maximumAttempts, tokens: allowance.tokens - plan.combined.reservedTokens,
|
|
69
|
+
usdMicros: allowance.usdMicros - plan.combined.reservedUsdMicros };
|
|
70
|
+
return { allowance: { ...allowance }, headroom, fits: headroom.calls >= 0 && headroom.tokens >= 0 && headroom.usdMicros >= 0 };
|
|
71
|
+
}
|
|
72
|
+
/** A fresh ledger's allowance for an approval: the first approval's thresholds net of its attested prior spend floors. */
|
|
73
|
+
export function d17FreshAllowance(approval) {
|
|
74
|
+
return heldoutCollectionAllowance(approval, { studyUsdMicros: Math.ceil(approval.priorStudySpendUsd * 1_000_000),
|
|
75
|
+
portfolioUsdMicros: Math.ceil(approval.priorPortfolioSpendUsd * 1_000_000), studyCalls: 0, studyReservedTokens: 0,
|
|
76
|
+
counterBlocked: false, attempts: [], journalDigests: [], runs: [] });
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The staged corpus is the diagnostic corpus for the same seed. Any attempt in the ledger on this corpus under another
|
|
80
|
+
* preregistration (for example a diagnostic run that saw test rows) means the seed is spent: use a fresh seed.
|
|
81
|
+
*/
|
|
82
|
+
export function assertD17SeedUnused(attempts, approval) {
|
|
83
|
+
if (attempts.some(attempt => attempt.corpusDigest === approval.corpusDigest && attempt.preregistrationDigest !== approval.preregistrationDigest)) {
|
|
84
|
+
throw new Error('D17 seed reused: this corpus already has observations under another preregistration');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=staged.js.map
|