@dailephd/my-dev-kit-lab 0.4.4 → 0.4.5
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 +468 -0
- package/README.md +3 -1
- package/dist/scripts/report-context-integrity-smoke.js +70 -0
- package/dist/src/evaluation/ecosystemFixtures/index.js +3 -0
- package/dist/src/evaluation/ecosystemFixtures/loadContextIntegrityFixture.js +102 -0
- package/dist/src/evaluation/ecosystemFixtures/manifestTypes.js +1 -0
- package/dist/src/evaluation/ecosystemFixtures/validateManifest.js +82 -0
- package/dist/src/evaluation/ecosystemFixtures/verifyFixtureHashes.js +45 -0
- package/dist/src/evaluation/stageContextMetrics/calculateAllocationMetrics.js +169 -0
- package/dist/src/evaluation/stageContextMetrics/calculateConditionCoverageMetrics.js +74 -0
- package/dist/src/evaluation/stageContextMetrics/calculateProducerConditionAgreement.js +113 -0
- package/dist/src/evaluation/stageContextMetrics/calculateReadinessAgreement.js +60 -0
- package/dist/src/evaluation/stageContextMetrics/calculateRunIntegrityAgreement.js +309 -0
- package/dist/src/evaluation/stageContextMetrics/calculateSupplementalRawAgreement.js +12 -2
- package/dist/src/evaluation/stageContextMetrics/calculateTruncationClassification.js +100 -0
- package/dist/src/evaluation/stageContextMetrics/evaluateProducerReadinessBridge.js +76 -5
- package/dist/src/evaluation/stageContextMetrics/index.js +4 -0
- package/dist/src/evaluation/stageContextMetrics/runIntegrityAgreementTypes.js +1 -0
- package/dist/src/evaluation/stageContextSelectors/contextArtifactConsistency.js +7 -0
- package/dist/src/evaluation/stageContextSelectors/index.js +1 -0
- package/dist/src/evaluation/stageContextSelectors/orchestratorRunIntegritySelectors.js +64 -0
- package/dist/src/evaluation/upstreamArtifacts/index.js +2 -0
- package/dist/src/evaluation/upstreamArtifacts/orchestratorRunIntegrityV1.js +33 -0
- package/dist/src/evaluation/upstreamArtifacts/readOrchestratorRunIntegrityV1.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/validateMyDevKitContextCapsuleV1.js +59 -2
- package/dist/src/evaluation/upstreamArtifacts/validateMyDevKitRetrievalAuditRecordV1.js +6 -1
- package/dist/src/evaluation/upstreamArtifacts/validateOrchestratorRunIntegrityV1.js +177 -0
- package/dist/src/report/experiments/buildContextIntegrityReport.js +204 -0
- package/dist/src/report/experiments/contextIntegrityReportModel.js +1 -0
- package/dist/src/report/experiments/index.js +5 -0
- package/dist/src/report/experiments/renderContextIntegrityHtml.js +98 -0
- package/dist/src/report/experiments/renderContextIntegrityJsonReport.js +3 -0
- package/dist/src/report/experiments/renderContextIntegrityText.js +111 -0
- package/dist/src/securityValidation/packageChecks/requiredPackageContents.js +33 -0
- package/dist/src/securityValidation/packageChecks/runPackageChecks.js +11 -5
- package/docs/METRICS.md +83 -0
- package/package.json +4 -2
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/corrected-replay/derived/run-integrity-evidence.json +99 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/corrected-replay/producer/implementation-audit.json +1585 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/corrected-replay/producer/implementation-capsule.json +11455 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/00-request.txt +1 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/architecture-context-packet.txt +82 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/behavior-model.txt +104 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/final-report.txt +41 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/implementation-context-packet.txt +114 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/implementation-report.txt +92 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/judge-report.txt +34 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/pseudocode-packet.txt +244 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/request-brief.txt +40 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/test-context-packet.txt +93 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/test-implementation-report.txt +69 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/test-strategy-packet.txt +354 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/verification-report.txt +85 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/derived/run-integrity-evidence.json +98 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/architecture-audit.json +1169 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/architecture-request.json +29 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/implementation-audit.json +1494 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/implementation-capsule.json +11364 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/implementation-request.json +33 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/test-request.json +74 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/reports/architecture-context-retrieval-report.txt +58 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/reports/implementation-context-retrieval-report.txt +75 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/reports/test-context-retrieval-report.txt +84 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/run.json +62 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/tool-versions/my-dev-kit-version.txt +1 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/tool-versions/orchestrator-version.txt +1 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/manifests/corrected-replay-manifest.json +19 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/manifests/failed-run-manifest.json +56 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.4/PROVENANCE.txt +18 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.4/context-capsule/complete-v1.0.0.json +556 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.4/retrieval-audit-record/complete-v1.0.0.json +238 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.3/run-integrity/PROVENANCE.txt +31 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.3/run-integrity/ready-pass-final-pass.json +132 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.3/run-integrity/refresh-required-need-context.json +146 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { selectStageMayRenderNormalPrompt } from "../stageContextSelectors/orchestratorRunIntegritySelectors.js";
|
|
2
|
+
const CONTEXT_SENSITIVE_STAGE_NAMES = ["implementation", "test-implementation"];
|
|
3
|
+
function contradiction(code, fieldPath, expected, observed, reason) {
|
|
4
|
+
return { code, fieldPath, expected, observed, reason };
|
|
5
|
+
}
|
|
6
|
+
// --- section 19: readiness vs prompt mode ----------------------------------------------
|
|
7
|
+
export function calculateReadinessPromptAgreement(evidence, stageName) {
|
|
8
|
+
const readinessClassification = evidence.gate.readinessClassification;
|
|
9
|
+
const stageMayRenderNormalPrompt = selectStageMayRenderNormalPrompt(evidence, stageName) ?? null;
|
|
10
|
+
if (!CONTEXT_SENSITIVE_STAGE_NAMES.includes(stageName)) {
|
|
11
|
+
return {
|
|
12
|
+
availability: "not-applicable",
|
|
13
|
+
outcome: "not-applicable",
|
|
14
|
+
readinessClassification,
|
|
15
|
+
stageMayRenderNormalPrompt,
|
|
16
|
+
contradictions: [],
|
|
17
|
+
reason: `Stage "${stageName}" is not a context-sensitive stage; the gate does not attach a prompt-mode decision to it.`
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (stageMayRenderNormalPrompt === null) {
|
|
21
|
+
return {
|
|
22
|
+
availability: "unavailable",
|
|
23
|
+
outcome: "insufficient-evidence",
|
|
24
|
+
readinessClassification,
|
|
25
|
+
stageMayRenderNormalPrompt: null,
|
|
26
|
+
contradictions: [],
|
|
27
|
+
reason: "No prompt-mode decision was derivable for this stage."
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const contradictions = [];
|
|
31
|
+
if (readinessClassification === "ready" && !stageMayRenderNormalPrompt) {
|
|
32
|
+
contradictions.push(contradiction("READY_BUT_PROMPT_NOT_NORMAL", "gate.readinessClassification", "ready", "refresh-only", "Readiness is ready but this stage may not render its normal prompt."));
|
|
33
|
+
}
|
|
34
|
+
if (readinessClassification === "refresh-required" && stageMayRenderNormalPrompt) {
|
|
35
|
+
contradictions.push(contradiction("REFRESH_REQUIRED_BUT_PROMPT_NORMAL", "gate.readinessClassification", "refresh-required", "normal", "Readiness is refresh-required but this stage may still render its normal prompt."));
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
availability: "available",
|
|
39
|
+
outcome: contradictions.length > 0 ? "contradiction" : "agreement",
|
|
40
|
+
readinessClassification,
|
|
41
|
+
stageMayRenderNormalPrompt,
|
|
42
|
+
contradictions,
|
|
43
|
+
reason: contradictions.length > 0 ? "Readiness classification and stage prompt-mode evidence disagree." : null
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// --- section 20: readiness vs expected judge verdict ------------------------------------
|
|
47
|
+
export function calculateReadinessExpectedJudgeAgreement(evidence) {
|
|
48
|
+
const { contextReady, expectedJudgeVerdict } = evidence.gate;
|
|
49
|
+
const contradictions = [];
|
|
50
|
+
if (contextReady && expectedJudgeVerdict !== "PASS") {
|
|
51
|
+
contradictions.push(contradiction("CONTEXT_READY_BUT_EXPECTED_NOT_PASS", "gate.expectedJudgeVerdict", "PASS", expectedJudgeVerdict, "contextReady is true but expectedJudgeVerdict is not PASS."));
|
|
52
|
+
}
|
|
53
|
+
if (!contextReady && expectedJudgeVerdict !== "NEED_CONTEXT") {
|
|
54
|
+
contradictions.push(contradiction("CONTEXT_NOT_READY_BUT_EXPECTED_NOT_NEED_CONTEXT", "gate.expectedJudgeVerdict", "NEED_CONTEXT", expectedJudgeVerdict, "contextReady is false but expectedJudgeVerdict is not NEED_CONTEXT."));
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
availability: "available",
|
|
58
|
+
outcome: contradictions.length > 0 ? "contradiction" : "agreement",
|
|
59
|
+
contextReady,
|
|
60
|
+
expectedJudgeVerdict,
|
|
61
|
+
contradictions,
|
|
62
|
+
reason: contradictions.length > 0 ? "The gate's own contextReady/expectedJudgeVerdict invariant does not hold for this evidence." : null
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// --- section 21: expected vs parsed (actual) judge verdict -------------------------------
|
|
66
|
+
export function calculateExpectedActualJudgeAgreement(evidence) {
|
|
67
|
+
const judgeIntegrity = evidence.judgeIntegrity;
|
|
68
|
+
if (judgeIntegrity === undefined) {
|
|
69
|
+
return {
|
|
70
|
+
availability: "unavailable",
|
|
71
|
+
outcome: "insufficient-evidence",
|
|
72
|
+
expectedJudgeVerdict: evidence.gate.expectedJudgeVerdict,
|
|
73
|
+
authoredJudgeVerdict: null,
|
|
74
|
+
judgeVerdictParseStatus: null,
|
|
75
|
+
judgeVerdictAccepted: null,
|
|
76
|
+
contradictions: [],
|
|
77
|
+
reason: "No judgeIntegrity evidence was supplied."
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const contradictions = [];
|
|
81
|
+
const { expectedJudgeVerdict, authoredJudgeVerdict, judgeVerdictParseStatus, judgeVerdictAccepted, judgeVerdictMatchesExpected, blockingCodes } = judgeIntegrity;
|
|
82
|
+
if (judgeVerdictParseStatus === "unknown-verdict") {
|
|
83
|
+
contradictions.push(contradiction("JUDGE_VERDICT_UNKNOWN", "judgeIntegrity.judgeVerdictParseStatus", "parsed", "unknown-verdict", "Judge report declares an unrecognized verdict."));
|
|
84
|
+
}
|
|
85
|
+
else if (judgeVerdictParseStatus === "missing-verdict") {
|
|
86
|
+
contradictions.push(contradiction("JUDGE_VERDICT_MISSING", "judgeIntegrity.judgeVerdictParseStatus", "parsed", "missing-verdict", "Judge report does not declare a verdict."));
|
|
87
|
+
}
|
|
88
|
+
else if (judgeVerdictParseStatus === "missing-artifact") {
|
|
89
|
+
contradictions.push(contradiction("JUDGE_REPORT_MISSING", "judgeIntegrity.judgeArtifactPresent", "true", "false", "No judge report artifact exists."));
|
|
90
|
+
}
|
|
91
|
+
else if (authoredJudgeVerdict === "PASS" && expectedJudgeVerdict === "NEED_CONTEXT") {
|
|
92
|
+
// The exact upstream contradiction code (src/judgeIntegrity.ts
|
|
93
|
+
// JUDGE_VERDICT_CONTRADICTS_RUN_INTEGRITY), preserved verbatim when present.
|
|
94
|
+
contradictions.push(contradiction(blockingCodes.includes("JUDGE_VERDICT_CONTRADICTS_RUN_INTEGRITY") ? "JUDGE_VERDICT_CONTRADICTS_RUN_INTEGRITY" : "AUTHORED_PASS_CONTRADICTS_EXPECTED_NEED_CONTEXT", "judgeIntegrity.authoredJudgeVerdict", "NEED_CONTEXT", "PASS", 'Judge report authored "PASS" but canonical readiness still requires NEED_CONTEXT.'));
|
|
95
|
+
}
|
|
96
|
+
else if (judgeVerdictAccepted && judgeVerdictMatchesExpected === false && authoredJudgeVerdict !== null) {
|
|
97
|
+
// A syntactically valid, accepted verdict that legitimately differs from the expected
|
|
98
|
+
// one without being the PASS/NEED_CONTEXT contradiction above (e.g. a correction-route
|
|
99
|
+
// verdict, or a terminal BLOCKED/SCOPE_VIOLATION verdict) is not itself an integrity
|
|
100
|
+
// contradiction -- it is the normal correction-required or blocked shape.
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
availability: "available",
|
|
104
|
+
outcome: contradictions.length > 0 ? "contradiction" : "agreement",
|
|
105
|
+
expectedJudgeVerdict,
|
|
106
|
+
authoredJudgeVerdict,
|
|
107
|
+
judgeVerdictParseStatus,
|
|
108
|
+
judgeVerdictAccepted,
|
|
109
|
+
contradictions,
|
|
110
|
+
reason: contradictions.length > 0 ? contradictions[0].reason : null
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// --- section 22: judge verdict vs correction route ---------------------------------------
|
|
114
|
+
const TERMINAL_BLOCKED_VERDICTS = ["SCOPE_VIOLATION", "BLOCKED"];
|
|
115
|
+
export function calculateJudgeCorrectionAgreement(evidence) {
|
|
116
|
+
const judgeIntegrity = evidence.judgeIntegrity;
|
|
117
|
+
if (judgeIntegrity === undefined) {
|
|
118
|
+
return {
|
|
119
|
+
availability: "unavailable",
|
|
120
|
+
outcome: "insufficient-evidence",
|
|
121
|
+
authoredJudgeVerdict: null,
|
|
122
|
+
correctionRequired: null,
|
|
123
|
+
acceptedCorrectionStage: null,
|
|
124
|
+
routedStage: null,
|
|
125
|
+
contradictions: [],
|
|
126
|
+
reason: "No judgeIntegrity evidence was supplied."
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
const { authoredJudgeVerdict, correctionRequired, correctionBlocked, acceptedCorrectionStage, acceptedCorrectionRoute } = judgeIntegrity;
|
|
130
|
+
const routedStage = acceptedCorrectionRoute?.routedStage ?? null;
|
|
131
|
+
const contradictions = [];
|
|
132
|
+
if (authoredJudgeVerdict === "PASS" && acceptedCorrectionRoute !== null) {
|
|
133
|
+
contradictions.push(contradiction("PASS_WITH_ACTIVE_CORRECTION_ROUTE", "judgeIntegrity.acceptedCorrectionRoute", "null", "active", "Judge verdict is PASS but an active correction route is present."));
|
|
134
|
+
}
|
|
135
|
+
if (authoredJudgeVerdict !== null &&
|
|
136
|
+
authoredJudgeVerdict !== "PASS" &&
|
|
137
|
+
!TERMINAL_BLOCKED_VERDICTS.includes(authoredJudgeVerdict) &&
|
|
138
|
+
!correctionBlocked &&
|
|
139
|
+
correctionRequired &&
|
|
140
|
+
acceptedCorrectionRoute === null) {
|
|
141
|
+
contradictions.push(contradiction("CORRECTIVE_VERDICT_WITHOUT_ROUTE", "judgeIntegrity.acceptedCorrectionRoute", "active", "null", `Judge verdict "${authoredJudgeVerdict}" requires correction but no correction route is present.`));
|
|
142
|
+
}
|
|
143
|
+
if (acceptedCorrectionStage !== null && routedStage !== null && acceptedCorrectionStage !== routedStage) {
|
|
144
|
+
contradictions.push(contradiction("CORRECTION_DESTINATION_MISMATCH", "judgeIntegrity.acceptedCorrectionStage", routedStage, acceptedCorrectionStage, "acceptedCorrectionStage does not match the structured correction route's routedStage."));
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
availability: "available",
|
|
148
|
+
outcome: contradictions.length > 0 ? "contradiction" : "agreement",
|
|
149
|
+
authoredJudgeVerdict,
|
|
150
|
+
correctionRequired,
|
|
151
|
+
acceptedCorrectionStage,
|
|
152
|
+
routedStage,
|
|
153
|
+
contradictions,
|
|
154
|
+
reason: contradictions.length > 0 ? contradictions[0].reason : null
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
// --- section 23: readiness/judge vs final-report eligibility -----------------------------
|
|
158
|
+
export function calculateJudgeFinalEligibilityAgreement(evidence) {
|
|
159
|
+
const judgeIntegrity = evidence.judgeIntegrity;
|
|
160
|
+
if (judgeIntegrity === undefined) {
|
|
161
|
+
return {
|
|
162
|
+
availability: "unavailable",
|
|
163
|
+
outcome: "insufficient-evidence",
|
|
164
|
+
authoredJudgeVerdict: null,
|
|
165
|
+
judgeVerdictAccepted: null,
|
|
166
|
+
judgeVerdictMatchesExpected: null,
|
|
167
|
+
finalReportEligible: null,
|
|
168
|
+
contradictions: [],
|
|
169
|
+
reason: "No judgeIntegrity evidence was supplied."
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const { authoredJudgeVerdict, judgeVerdictAccepted, judgeVerdictMatchesExpected, finalReportEligible, judgeVerdictParseStatus } = judgeIntegrity;
|
|
173
|
+
const contradictions = [];
|
|
174
|
+
if (finalReportEligible && authoredJudgeVerdict !== "PASS") {
|
|
175
|
+
contradictions.push(contradiction("ELIGIBLE_WITH_NON_PASS_JUDGE", "judgeIntegrity.finalReportEligible", "PASS", authoredJudgeVerdict, "finalReportEligible is true but the authored judge verdict is not PASS."));
|
|
176
|
+
}
|
|
177
|
+
if (finalReportEligible && judgeVerdictParseStatus !== "parsed") {
|
|
178
|
+
contradictions.push(contradiction("ELIGIBLE_WITH_MALFORMED_OR_MISSING_JUDGE", "judgeIntegrity.finalReportEligible", "parsed", judgeVerdictParseStatus, "finalReportEligible is true but the judge verdict was not successfully parsed."));
|
|
179
|
+
}
|
|
180
|
+
if (finalReportEligible && !judgeVerdictAccepted) {
|
|
181
|
+
contradictions.push(contradiction("ELIGIBLE_WITH_UNACCEPTED_JUDGE", "judgeIntegrity.finalReportEligible", "true", "false", "finalReportEligible is true but judgeVerdictAccepted is false."));
|
|
182
|
+
}
|
|
183
|
+
if (finalReportEligible && judgeVerdictMatchesExpected === false) {
|
|
184
|
+
contradictions.push(contradiction("ELIGIBLE_WITH_UNMATCHED_EXPECTED_VERDICT", "judgeIntegrity.finalReportEligible", "true", "false", "finalReportEligible is true but judgeVerdictMatchesExpected is false."));
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
availability: "available",
|
|
188
|
+
outcome: contradictions.length > 0 ? "contradiction" : "agreement",
|
|
189
|
+
authoredJudgeVerdict,
|
|
190
|
+
judgeVerdictAccepted,
|
|
191
|
+
judgeVerdictMatchesExpected,
|
|
192
|
+
finalReportEligible,
|
|
193
|
+
contradictions,
|
|
194
|
+
reason: contradictions.length > 0 ? contradictions[0].reason : null
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
// --- section 24: final eligibility vs final artifact and verdict -------------------------
|
|
198
|
+
export function calculateEligibilityFinalArtifactAgreement(evidence) {
|
|
199
|
+
const eligibility = evidence.finalReportEligibility;
|
|
200
|
+
const finalArtifactPresent = evidence.finalArtifactPresent;
|
|
201
|
+
const finalArtifactVerdict = evidence.finalArtifactVerdict ?? null;
|
|
202
|
+
if (eligibility === undefined || finalArtifactPresent === undefined) {
|
|
203
|
+
return {
|
|
204
|
+
availability: "unavailable",
|
|
205
|
+
outcome: "insufficient-evidence",
|
|
206
|
+
eligible: eligibility?.eligible ?? null,
|
|
207
|
+
finalArtifactPresent: finalArtifactPresent ?? null,
|
|
208
|
+
finalArtifactVerdict,
|
|
209
|
+
contradictions: [],
|
|
210
|
+
reason: eligibility === undefined ? "No finalReportEligibility evidence was supplied." : "No finalArtifactPresent evidence was supplied."
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
const { eligible } = eligibility;
|
|
214
|
+
const contradictions = [];
|
|
215
|
+
if (eligible && !finalArtifactPresent) {
|
|
216
|
+
contradictions.push(contradiction("ELIGIBLE_BUT_ARTIFACT_MISSING", "finalArtifactPresent", "true", "false", "The run is final-report eligible but no final artifact is present."));
|
|
217
|
+
}
|
|
218
|
+
if (!eligible && finalArtifactPresent) {
|
|
219
|
+
contradictions.push(contradiction("INELIGIBLE_BUT_ARTIFACT_PRESENT", "finalArtifactPresent", "false", "true", "The run is not final-report eligible but a final artifact is present."));
|
|
220
|
+
}
|
|
221
|
+
if (!eligible && finalArtifactVerdict === "PASS") {
|
|
222
|
+
// The required v0.4.5 failure detection: NEED_CONTEXT (or any other ineligible state)
|
|
223
|
+
// followed by a normal PASS final report must report an integrity contradiction.
|
|
224
|
+
const expectedJudge = evidence.gate.expectedJudgeVerdict;
|
|
225
|
+
contradictions.push(contradiction(expectedJudge === "NEED_CONTEXT" ? "NEED_CONTEXT_FOLLOWED_BY_FINAL_PASS" : "INELIGIBLE_WITH_FINAL_PASS", "finalArtifactVerdict", "not PASS", "PASS", expectedJudge === "NEED_CONTEXT"
|
|
226
|
+
? "Canonical readiness required NEED_CONTEXT, yet a final report with verdict PASS exists."
|
|
227
|
+
: "The run is not final-report eligible, yet a final report with verdict PASS exists."));
|
|
228
|
+
}
|
|
229
|
+
if (finalArtifactPresent && evidence.finalArtifactVerdict === undefined) {
|
|
230
|
+
contradictions.push(contradiction("FINAL_ARTIFACT_MALFORMED_VERDICT", "finalArtifactVerdict", "parsed", "undefined", "A final artifact is present but its verdict was not supplied."));
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
availability: "available",
|
|
234
|
+
outcome: contradictions.length > 0 ? "contradiction" : "agreement",
|
|
235
|
+
eligible,
|
|
236
|
+
finalArtifactPresent,
|
|
237
|
+
finalArtifactVerdict,
|
|
238
|
+
contradictions,
|
|
239
|
+
reason: contradictions.length > 0 ? contradictions[0].reason : null
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
// --- section 25: lifecycle integrity -----------------------------------------------------
|
|
243
|
+
export function calculateLifecycleIntegrityAgreement(evidence) {
|
|
244
|
+
if (evidence.lifecycle.length === 0) {
|
|
245
|
+
return { availability: "not-applicable", outcome: "not-applicable", entries: [], contradictions: [], reason: "No lifecycle evidence was supplied." };
|
|
246
|
+
}
|
|
247
|
+
const contradictions = [];
|
|
248
|
+
const entries = evidence.lifecycle.map((entry) => {
|
|
249
|
+
const completionBasis = entry.resolvedState !== "complete" ? "not-complete" : entry.manualRecord === null ? "artifact-presence-only" : "manual-record";
|
|
250
|
+
const markCompleteRejected = entry.manualRecord?.state === "complete" && entry.resolvedState !== "complete";
|
|
251
|
+
const stageContextBlocked = CONTEXT_SENSITIVE_STAGE_NAMES.includes(entry.stageName) &&
|
|
252
|
+
evidence.gate.blockedStageNames.includes(entry.stageName);
|
|
253
|
+
const finalReportIneligible = entry.stageName === "final-report" && evidence.finalReportEligibility?.eligible === false;
|
|
254
|
+
const shouldBeBlocked = stageContextBlocked || finalReportIneligible;
|
|
255
|
+
const bypassSucceeded = shouldBeBlocked && entry.resolvedState === "complete";
|
|
256
|
+
if (bypassSucceeded) {
|
|
257
|
+
contradictions.push(contradiction("MANUAL_MARK_COMPLETE_BYPASS_SUCCEEDED", `lifecycle[${entry.stageName}].resolvedState`, "blocked", "complete", `Stage "${entry.stageName}" should be run-integrity-blocked but resolved to "complete"${completionBasis === "artifact-presence-only" ? " through artifact presence alone" : " despite a manual mark-complete record"}.`));
|
|
258
|
+
}
|
|
259
|
+
return { artifactFile: entry.artifactFile, stageName: entry.stageName, resolvedState: entry.resolvedState, completionBasis, markCompleteRejected, bypassSucceeded };
|
|
260
|
+
});
|
|
261
|
+
return {
|
|
262
|
+
availability: "available",
|
|
263
|
+
outcome: contradictions.length > 0 ? "contradiction" : "agreement",
|
|
264
|
+
entries,
|
|
265
|
+
contradictions,
|
|
266
|
+
reason: contradictions.length > 0 ? "At least one lifecycle entry resolved to complete despite required run-integrity blocking." : null
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
// --- section 26: end-to-end aggregate summary ---------------------------------------------
|
|
270
|
+
function summarize(producerReadinessOutcome, readinessPrompt, readinessExpectedJudge, expectedActualJudge, judgeCorrection, judgeFinalEligibility, eligibilityFinalArtifact, lifecycleIntegrity) {
|
|
271
|
+
const componentOutcomes = {
|
|
272
|
+
producerReadiness: producerReadinessOutcome,
|
|
273
|
+
readinessPrompt,
|
|
274
|
+
readinessExpectedJudge,
|
|
275
|
+
expectedActualJudge,
|
|
276
|
+
judgeCorrection,
|
|
277
|
+
judgeFinalEligibility,
|
|
278
|
+
eligibilityFinalArtifact,
|
|
279
|
+
lifecycleIntegrity
|
|
280
|
+
};
|
|
281
|
+
const contradictingComponents = Object.keys(componentOutcomes).filter((key) => componentOutcomes[key] === "contradiction");
|
|
282
|
+
const category = contradictingComponents.length > 0
|
|
283
|
+
? "contradiction-present"
|
|
284
|
+
: Object.values(componentOutcomes).some((o) => o === "insufficient-evidence")
|
|
285
|
+
? "insufficient-evidence"
|
|
286
|
+
: Object.values(componentOutcomes).some((o) => o === "unsupported-legacy-evidence")
|
|
287
|
+
? "unsupported-legacy-evidence"
|
|
288
|
+
: "full-agreement";
|
|
289
|
+
return { category, componentOutcomes, contradictingComponents };
|
|
290
|
+
}
|
|
291
|
+
export function evaluateRunIntegrity(evidence, stageName, producerReadinessOutcome = "not-applicable") {
|
|
292
|
+
const readinessPrompt = calculateReadinessPromptAgreement(evidence, stageName);
|
|
293
|
+
const readinessExpectedJudge = calculateReadinessExpectedJudgeAgreement(evidence);
|
|
294
|
+
const expectedActualJudge = calculateExpectedActualJudgeAgreement(evidence);
|
|
295
|
+
const judgeCorrection = calculateJudgeCorrectionAgreement(evidence);
|
|
296
|
+
const judgeFinalEligibility = calculateJudgeFinalEligibilityAgreement(evidence);
|
|
297
|
+
const eligibilityFinalArtifact = calculateEligibilityFinalArtifactAgreement(evidence);
|
|
298
|
+
const lifecycleIntegrity = calculateLifecycleIntegrityAgreement(evidence);
|
|
299
|
+
return {
|
|
300
|
+
readinessPrompt,
|
|
301
|
+
readinessExpectedJudge,
|
|
302
|
+
expectedActualJudge,
|
|
303
|
+
judgeCorrection,
|
|
304
|
+
judgeFinalEligibility,
|
|
305
|
+
eligibilityFinalArtifact,
|
|
306
|
+
lifecycleIntegrity,
|
|
307
|
+
endToEndSummary: summarize(producerReadinessOutcome, readinessPrompt.outcome, readinessExpectedJudge.outcome, expectedActualJudge.outcome, judgeCorrection.outcome, judgeFinalEligibility.outcome, eligibilityFinalArtifact.outcome, lifecycleIntegrity.outcome)
|
|
308
|
+
};
|
|
309
|
+
}
|
|
@@ -3,7 +3,8 @@ function extractRawIdentity(artifact) {
|
|
|
3
3
|
projectRoot: artifact.index.projectRoot,
|
|
4
4
|
role: artifact.request.role,
|
|
5
5
|
freshnessState: artifact.freshness.state,
|
|
6
|
-
truncated: artifact.truncation.truncated
|
|
6
|
+
truncated: artifact.truncation.truncated,
|
|
7
|
+
requiredEvidenceLost: artifact.truncation.requiredEvidenceLost
|
|
7
8
|
};
|
|
8
9
|
}
|
|
9
10
|
function truncationToYesNo(value) {
|
|
@@ -26,7 +27,8 @@ export function calculateSupplementalRawAgreement(supplemental, raw) {
|
|
|
26
27
|
buildField("canonicalRepositoryIdentity", null, supplemental?.indexIdentity ?? null, reason),
|
|
27
28
|
buildField("role", null, supplemental?.role ?? null, reason),
|
|
28
29
|
buildField("freshness", null, supplemental?.freshness ?? null, reason),
|
|
29
|
-
buildField("requiredEvidenceTruncated", null, supplemental?.requiredEvidenceTruncated ?? null, reason)
|
|
30
|
+
buildField("requiredEvidenceTruncated", null, supplemental?.requiredEvidenceTruncated ?? null, reason),
|
|
31
|
+
buildField("requiredEvidenceLost", null, supplemental?.requiredEvidenceTruncated ?? null, reason)
|
|
30
32
|
];
|
|
31
33
|
return { fields, contradictions: [], upstreamProducerParityPreserved: null };
|
|
32
34
|
}
|
|
@@ -39,6 +41,14 @@ export function calculateSupplementalRawAgreement(supplemental, raw) {
|
|
|
39
41
|
fields.push(buildField("requiredEvidenceTruncated", truncationToYesNo(rawIdentity.truncated), supplemental.requiredEvidenceTruncated, supplemental.requiredEvidenceTruncated === "unknown"
|
|
40
42
|
? "The supplemental document declares truncation as \"unknown\", so agreement with the raw boolean cannot be determined."
|
|
41
43
|
: null));
|
|
44
|
+
// v0.4.5 Batch 2 (section 17): the stricter comparison against the Batch 1
|
|
45
|
+
// truncation.requiredEvidenceLost rollup, additive to the general "truncated" comparison
|
|
46
|
+
// above. Absent on legacy raw artifacts, never fabricated.
|
|
47
|
+
fields.push(buildField("requiredEvidenceLost", rawIdentity.requiredEvidenceLost === undefined ? null : truncationToYesNo(rawIdentity.requiredEvidenceLost), supplemental.requiredEvidenceTruncated, rawIdentity.requiredEvidenceLost === undefined
|
|
48
|
+
? "The raw artifact does not declare truncation.requiredEvidenceLost (legacy schema-major-1 evidence)."
|
|
49
|
+
: supplemental.requiredEvidenceTruncated === "unknown"
|
|
50
|
+
? "The supplemental document declares truncation as \"unknown\", so agreement with the raw boolean cannot be determined."
|
|
51
|
+
: null));
|
|
42
52
|
const contradictions = fields.filter((f) => f.availability === "available" && f.agreement === false);
|
|
43
53
|
return {
|
|
44
54
|
fields,
|
|
@@ -42,3 +42,103 @@ export function classifyTruncationRecord(record, sourceArtifact, sourceInstance)
|
|
|
42
42
|
export function classifyTruncationRecords(records, sourceArtifact, sourceInstance) {
|
|
43
43
|
return records.map((record) => classifyTruncationRecord(record, sourceArtifact, sourceInstance));
|
|
44
44
|
}
|
|
45
|
+
// v0.4.5 Batch 2: condition-aware truncation classification. Distinguishes the seven states
|
|
46
|
+
// required by the Batch 2 plan using only explicit upstream evidence (truncation.truncated,
|
|
47
|
+
// truncation.requiredEvidenceLost, ContextCapsule.groupTruncation's required/optional omitted
|
|
48
|
+
// counts, and roleConditionCoverage's lostRequiredCondition/lossReason). Never independently
|
|
49
|
+
// decides that a condition lost its last witness from a raw file count.
|
|
50
|
+
export function classifyConditionAwareTruncation(artifact, sourceArtifact, sourceInstance) {
|
|
51
|
+
const requiredEvidenceLost = artifact.truncation.requiredEvidenceLost;
|
|
52
|
+
const roleConditionCoverage = artifact.roleConditionCoverage;
|
|
53
|
+
const groupTruncation = "groupTruncation" in artifact ? artifact.groupTruncation : undefined;
|
|
54
|
+
const lostConditions = roleConditionCoverage?.filter((c) => c.lostRequiredCondition) ?? undefined;
|
|
55
|
+
const lostRequiredConditionIds = lostConditions?.map((c) => c.conditionId) ?? [];
|
|
56
|
+
const groupsWithBothOmissionFields = groupTruncation?.filter((g) => g.requiredOmittedCount !== undefined && g.optionalOmittedCount !== undefined);
|
|
57
|
+
const requiredOmittedTotal = groupsWithBothOmissionFields !== undefined && groupsWithBothOmissionFields.length === (groupTruncation?.length ?? -1) && groupTruncation.length > 0
|
|
58
|
+
? groupsWithBothOmissionFields.reduce((sum, g) => sum + (g.requiredOmittedCount ?? 0), 0)
|
|
59
|
+
: null;
|
|
60
|
+
const optionalOmittedTotal = groupsWithBothOmissionFields !== undefined && groupsWithBothOmissionFields.length === (groupTruncation?.length ?? -1) && groupTruncation.length > 0
|
|
61
|
+
? groupsWithBothOmissionFields.reduce((sum, g) => sum + (g.optionalOmittedCount ?? 0), 0)
|
|
62
|
+
: null;
|
|
63
|
+
const base = {
|
|
64
|
+
sourceArtifact,
|
|
65
|
+
sourceInstance,
|
|
66
|
+
requiredEvidenceLost: requiredEvidenceLost ?? null,
|
|
67
|
+
requiredOmittedTotal,
|
|
68
|
+
optionalOmittedTotal,
|
|
69
|
+
lostRequiredConditionIds
|
|
70
|
+
};
|
|
71
|
+
const hasAnyCurrentDiagnostics = requiredEvidenceLost !== undefined || roleConditionCoverage !== undefined || requiredOmittedTotal !== null;
|
|
72
|
+
if (!hasAnyCurrentDiagnostics) {
|
|
73
|
+
return {
|
|
74
|
+
...base,
|
|
75
|
+
availability: "unavailable",
|
|
76
|
+
state: "unsupported-legacy-diagnostics",
|
|
77
|
+
contradictionCodes: [],
|
|
78
|
+
reason: "No v1.10.3/v1.10.4 truncation or condition-coverage diagnostics were supplied (legacy schema-major-1 evidence)."
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const contradictionCodes = [];
|
|
82
|
+
if (requiredEvidenceLost === false && lostRequiredConditionIds.length > 0) {
|
|
83
|
+
contradictionCodes.push("REQUIRED_EVIDENCE_LOST_FALSE_BUT_CONDITION_LOSS_REPORTED");
|
|
84
|
+
}
|
|
85
|
+
if (requiredEvidenceLost === true &&
|
|
86
|
+
roleConditionCoverage !== undefined &&
|
|
87
|
+
lostRequiredConditionIds.length === 0 &&
|
|
88
|
+
roleConditionCoverage.filter((c) => c.required).every((c) => c.conditionSatisfied) &&
|
|
89
|
+
(requiredOmittedTotal === null || requiredOmittedTotal === 0)) {
|
|
90
|
+
contradictionCodes.push("REQUIRED_EVIDENCE_LOST_TRUE_BUT_ALL_REQUIRED_CONDITIONS_RETAINED");
|
|
91
|
+
}
|
|
92
|
+
if (contradictionCodes.length > 0) {
|
|
93
|
+
return {
|
|
94
|
+
...base,
|
|
95
|
+
availability: "available",
|
|
96
|
+
state: "contradictory-producer-evidence",
|
|
97
|
+
contradictionCodes,
|
|
98
|
+
reason: "Producer evidence is internally contradictory; both sides are retained rather than resolved by the lab."
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (lostRequiredConditionIds.length > 0) {
|
|
102
|
+
return {
|
|
103
|
+
...base,
|
|
104
|
+
availability: "available",
|
|
105
|
+
state: "required-condition-or-last-witness-loss",
|
|
106
|
+
contradictionCodes: [],
|
|
107
|
+
reason: `Explicit lostRequiredCondition evidence exists for: ${lostRequiredConditionIds.join(", ")}.`
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (requiredEvidenceLost === true || (requiredOmittedTotal !== null && requiredOmittedTotal > 0)) {
|
|
111
|
+
return {
|
|
112
|
+
...base,
|
|
113
|
+
availability: "available",
|
|
114
|
+
state: "required-evidence-loss",
|
|
115
|
+
contradictionCodes: [],
|
|
116
|
+
reason: "Required evidence loss is explicitly reported without condition-level detail."
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
if (requiredEvidenceLost === undefined && artifact.truncation.truncated) {
|
|
120
|
+
return {
|
|
121
|
+
...base,
|
|
122
|
+
availability: "available",
|
|
123
|
+
state: "unknown-criticality",
|
|
124
|
+
contradictionCodes: [],
|
|
125
|
+
reason: "General truncation occurred but the rollup requiredEvidenceLost field is absent, so required-versus-optional criticality cannot be determined."
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (artifact.truncation.truncated) {
|
|
129
|
+
return {
|
|
130
|
+
...base,
|
|
131
|
+
availability: "available",
|
|
132
|
+
state: "optional-only-truncation",
|
|
133
|
+
contradictionCodes: [],
|
|
134
|
+
reason: "Truncation occurred but no required evidence loss or condition loss was reported."
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
...base,
|
|
139
|
+
availability: "available",
|
|
140
|
+
state: "no-truncation",
|
|
141
|
+
contradictionCodes: [],
|
|
142
|
+
reason: null
|
|
143
|
+
};
|
|
144
|
+
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { collectSelectedOwnerEvidence, calculateOwnerMetrics } from "./calculateOwnerMetrics.js";
|
|
2
|
-
import { calculateAllocationFactsForGroups } from "./calculateAllocationMetrics.js";
|
|
3
|
-
import { classifyTruncationRecords } from "./calculateTruncationClassification.js";
|
|
2
|
+
import { calculateAllocationFactsForGroups, calculateGroupAllocationMetrics } from "./calculateAllocationMetrics.js";
|
|
3
|
+
import { classifyTruncationRecords, classifyConditionAwareTruncation } from "./calculateTruncationClassification.js";
|
|
4
|
+
import { calculateConditionCoverageMetrics } from "./calculateConditionCoverageMetrics.js";
|
|
5
|
+
import { calculateCapsuleAuditConditionAgreement, calculateProducerConditionAgreement, calculateRequiredEvidenceLossAgreement } from "./calculateProducerConditionAgreement.js";
|
|
4
6
|
import { calculateSupplementalRawAgreement } from "./calculateSupplementalRawAgreement.js";
|
|
5
|
-
import { calculateReadinessAgreementMetrics } from "./calculateReadinessAgreement.js";
|
|
7
|
+
import { calculateReadinessAgreementMetrics, calculateProducerReadinessRelationship } from "./calculateReadinessAgreement.js";
|
|
6
8
|
import { calculateCriticalityMetrics } from "./calculateCriticalityMetrics.js";
|
|
9
|
+
import { evaluateRunIntegrity } from "./calculateRunIntegrityAgreement.js";
|
|
7
10
|
function ownerExpectationsFor(expectations, sourceArtifact) {
|
|
8
11
|
return expectations?.ownerExpectations?.filter((e) => e.sourceArtifact === sourceArtifact);
|
|
9
12
|
}
|
|
@@ -36,7 +39,32 @@ function evaluateSide(input, expectations) {
|
|
|
36
39
|
: [];
|
|
37
40
|
const packetAgreement = input.packet !== undefined || rawForAgreement !== undefined ? calculateSupplementalRawAgreement(input.packet, rawForAgreement) : null;
|
|
38
41
|
const reportAgreement = input.report !== undefined || rawForAgreement !== undefined ? calculateSupplementalRawAgreement(input.report, rawForAgreement) : null;
|
|
39
|
-
|
|
42
|
+
// v0.4.5 Batch 2: allocation/condition-coverage evidence, computed once per side and
|
|
43
|
+
// carried through the result unchanged (never recomputed by a renderer or later batch).
|
|
44
|
+
const groupAllocationEvaluation = calculateGroupAllocationMetrics(capsule?.groupTruncation, input.role);
|
|
45
|
+
const conditionAwareTruncationEvaluation = truncationArtifact
|
|
46
|
+
? classifyConditionAwareTruncation(truncationArtifact, truncationSourceArtifact, input.role)
|
|
47
|
+
: null;
|
|
48
|
+
const roleConditionCoverage = capsule?.roleConditionCoverage ?? input.retrievalAuditRecord?.roleConditionCoverage;
|
|
49
|
+
const availableEvidenceGroupIds = capsule?.evidenceGroups.map((g) => g.id);
|
|
50
|
+
const conditionCoverageEvaluation = calculateConditionCoverageMetrics(roleConditionCoverage, availableEvidenceGroupIds);
|
|
51
|
+
const roleAdequacyStatus = (capsule ?? input.retrievalAuditRecord)?.roleAdequacy.status;
|
|
52
|
+
const producerConditionAgreement = calculateProducerConditionAgreement(roleAdequacyStatus, conditionCoverageEvaluation);
|
|
53
|
+
const requiredEvidenceLossAgreement = calculateRequiredEvidenceLossAgreement(truncationArtifact?.truncation.requiredEvidenceLost, conditionCoverageEvaluation, groupAllocationEvaluation.aggregate.totalRequiredOmitted);
|
|
54
|
+
const capsuleAuditConditionAgreement = calculateCapsuleAuditConditionAgreement(capsule, input.retrievalAuditRecord);
|
|
55
|
+
return {
|
|
56
|
+
ownerEvaluation,
|
|
57
|
+
allocationEvaluation,
|
|
58
|
+
truncationEvaluation,
|
|
59
|
+
packetAgreement,
|
|
60
|
+
reportAgreement,
|
|
61
|
+
groupAllocationEvaluation,
|
|
62
|
+
conditionAwareTruncationEvaluation,
|
|
63
|
+
conditionCoverageEvaluation,
|
|
64
|
+
producerConditionAgreement,
|
|
65
|
+
requiredEvidenceLossAgreement,
|
|
66
|
+
capsuleAuditConditionAgreement
|
|
67
|
+
};
|
|
40
68
|
}
|
|
41
69
|
// Builds bridge-evaluator input from an already-loaded combined-bounded-stage-context
|
|
42
70
|
// execution payload (Batch 3 section 12.1: "accept already-read raw, supplemental,
|
|
@@ -72,7 +100,10 @@ export function buildProducerReadinessBridgeInputFromCombinedPayload(payload, ex
|
|
|
72
100
|
};
|
|
73
101
|
}
|
|
74
102
|
export function evaluateProducerReadinessBridge(input) {
|
|
75
|
-
const hasAnyInput = input.implementation !== undefined ||
|
|
103
|
+
const hasAnyInput = input.implementation !== undefined ||
|
|
104
|
+
input.testImplementation !== undefined ||
|
|
105
|
+
input.readiness !== undefined ||
|
|
106
|
+
input.runIntegrityEvidence !== undefined;
|
|
76
107
|
if (!hasAnyInput) {
|
|
77
108
|
return {
|
|
78
109
|
status: "not-applicable",
|
|
@@ -81,6 +112,8 @@ export function evaluateProducerReadinessBridge(input) {
|
|
|
81
112
|
testImplementation: null,
|
|
82
113
|
readinessAgreement: null,
|
|
83
114
|
criticalityEvaluation: null,
|
|
115
|
+
producerReadinessRelationship: null,
|
|
116
|
+
runIntegrityEvaluation: null,
|
|
84
117
|
warnings: [],
|
|
85
118
|
evidenceReferences: []
|
|
86
119
|
};
|
|
@@ -114,6 +147,42 @@ export function evaluateProducerReadinessBridge(input) {
|
|
|
114
147
|
input.implementation?.retrievalAuditRecord?.responsibilityMappings.mappings ??
|
|
115
148
|
input.implementation?.contextCapsule?.responsibilityMappings.mappings;
|
|
116
149
|
const criticalityEvaluation = calculateCriticalityMetrics(criticalityMappings, input.expectations.producerReadinessExpectations?.criticalityExpectations);
|
|
150
|
+
// v0.4.5 Batch 2: producer role adequacy vs supplied orchestrator readiness. Selects the
|
|
151
|
+
// side input.readiness.kind actually applies to when available, otherwise falls back to
|
|
152
|
+
// the same test-implementation-preferred precedence as criticalityEvaluation above.
|
|
153
|
+
const readinessSideRole = input.readiness?.kind === "implementation" || input.readiness?.kind === "test" ? input.readiness.kind : undefined;
|
|
154
|
+
const readinessSideEvaluation = readinessSideRole === "implementation" ? implementation : readinessSideRole === "test" ? testImplementation : (testImplementation ?? implementation);
|
|
155
|
+
const readinessSideRawArtifact = readinessSideEvaluation?.role === "implementation"
|
|
156
|
+
? (input.implementation?.contextCapsule ?? input.implementation?.retrievalAuditRecord)
|
|
157
|
+
: readinessSideEvaluation?.role === "test-implementation"
|
|
158
|
+
? (input.testImplementation?.contextCapsule ?? input.testImplementation?.retrievalAuditRecord)
|
|
159
|
+
: undefined;
|
|
160
|
+
// calculateProducerReadinessRelationship short-circuits before touching this argument
|
|
161
|
+
// whenever roleAdequacyStatus is undefined, so a placeholder is safe when no side applies.
|
|
162
|
+
const placeholderProducerConditionAgreement = {
|
|
163
|
+
availability: "unavailable",
|
|
164
|
+
outcome: "insufficient-evidence",
|
|
165
|
+
observedRoleAdequacyStatus: null,
|
|
166
|
+
contradictionCodes: [],
|
|
167
|
+
reason: "No producer side applies to the supplied readiness result."
|
|
168
|
+
};
|
|
169
|
+
const producerReadinessRelationship = calculateProducerReadinessRelationship(readinessSideRawArtifact?.roleAdequacy.status, readinessSideEvaluation?.producerConditionAgreement ?? placeholderProducerConditionAgreement, input.readiness);
|
|
170
|
+
// v0.4.5 Batch 3: bounded orchestrator run-integrity evidence and agreement, computed
|
|
171
|
+
// once here and carried through unchanged. Stage selection follows the same
|
|
172
|
+
// applicableContextKinds the gate itself declares (implementation preferred, since the
|
|
173
|
+
// gate blocks implementation before test-implementation in workflow order); the
|
|
174
|
+
// producerReadinessRelationship outcome already computed above feeds the end-to-end
|
|
175
|
+
// summary's "producerReadiness" component rather than being recalculated.
|
|
176
|
+
let runIntegrityEvaluation = null;
|
|
177
|
+
if (input.runIntegrityEvidence !== undefined) {
|
|
178
|
+
const gate = input.runIntegrityEvidence.gate;
|
|
179
|
+
const stageName = gate.applicableContextKinds.includes("implementation")
|
|
180
|
+
? "implementation"
|
|
181
|
+
: gate.applicableContextKinds.includes("test")
|
|
182
|
+
? "test-implementation"
|
|
183
|
+
: gate.mode;
|
|
184
|
+
runIntegrityEvaluation = evaluateRunIntegrity(input.runIntegrityEvidence, stageName, producerReadinessRelationship.outcome);
|
|
185
|
+
}
|
|
117
186
|
return {
|
|
118
187
|
status: "evaluated",
|
|
119
188
|
reason: null,
|
|
@@ -121,6 +190,8 @@ export function evaluateProducerReadinessBridge(input) {
|
|
|
121
190
|
testImplementation,
|
|
122
191
|
readinessAgreement,
|
|
123
192
|
criticalityEvaluation,
|
|
193
|
+
producerReadinessRelationship,
|
|
194
|
+
runIntegrityEvaluation,
|
|
124
195
|
warnings,
|
|
125
196
|
evidenceReferences
|
|
126
197
|
};
|
|
@@ -15,3 +15,7 @@ export { calculateSupplementalRawAgreement } from "./calculateSupplementalRawAgr
|
|
|
15
15
|
export { calculateReadinessStructuralAgreement, calculateReadinessDecisionAgreement, calculateInvalidReady, calculateValidBlocked, calculateReadinessAgreementMetrics } from "./calculateReadinessAgreement.js";
|
|
16
16
|
export { calculateCriticalityMetrics } from "./calculateCriticalityMetrics.js";
|
|
17
17
|
export { evaluateProducerReadinessBridge, buildProducerReadinessBridgeInputFromCombinedPayload } from "./evaluateProducerReadinessBridge.js";
|
|
18
|
+
export { calculateGroupAllocationMetrics } from "./calculateAllocationMetrics.js";
|
|
19
|
+
export { calculateConditionCoverageMetrics } from "./calculateConditionCoverageMetrics.js";
|
|
20
|
+
export { calculateProducerConditionAgreement, calculateRequiredEvidenceLossAgreement, calculateCapsuleAuditConditionAgreement } from "./calculateProducerConditionAgreement.js";
|
|
21
|
+
export { calculateReadinessPromptAgreement, calculateReadinessExpectedJudgeAgreement, calculateExpectedActualJudgeAgreement, calculateJudgeCorrectionAgreement, calculateJudgeFinalEligibilityAgreement, calculateEligibilityFinalArtifactAgreement, calculateLifecycleIntegrityAgreement, evaluateRunIntegrity } from "./calculateRunIntegrityAgreement.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -38,6 +38,13 @@ export function checkMyDevKitContextArtifactConsistency(capsule, audit) {
|
|
|
38
38
|
capsuleValue: capsule.roleContext,
|
|
39
39
|
auditValue: audit.roleContext
|
|
40
40
|
},
|
|
41
|
+
// Both absent is a compatible legacy pair. One absent and one present is a
|
|
42
|
+
// contradiction; absence is never normalized to an empty current result.
|
|
43
|
+
{
|
|
44
|
+
fieldPath: "roleConditionCoverage",
|
|
45
|
+
capsuleValue: (capsule.roleConditionCoverage ?? null),
|
|
46
|
+
auditValue: (audit.roleConditionCoverage ?? null)
|
|
47
|
+
},
|
|
41
48
|
{
|
|
42
49
|
fieldPath: "responsibilityMappings",
|
|
43
50
|
capsuleValue: capsule.responsibilityMappings,
|