@dailephd/my-dev-kit-lab 0.4.3 → 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 +8 -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/stageContextExpectations/producerReadinessExpectationTypes.js +8 -0
- package/dist/src/evaluation/stageContextExpectations/validation.js +200 -0
- package/dist/src/evaluation/stageContextMetrics/calculateAllocationMetrics.js +265 -0
- package/dist/src/evaluation/stageContextMetrics/calculateConditionCoverageMetrics.js +74 -0
- package/dist/src/evaluation/stageContextMetrics/calculateCriticalityMetrics.js +112 -0
- package/dist/src/evaluation/stageContextMetrics/calculateOwnerMetrics.js +84 -0
- package/dist/src/evaluation/stageContextMetrics/calculateProducerConditionAgreement.js +113 -0
- package/dist/src/evaluation/stageContextMetrics/calculateReadinessAgreement.js +212 -0
- package/dist/src/evaluation/stageContextMetrics/calculateRunIntegrityAgreement.js +309 -0
- package/dist/src/evaluation/stageContextMetrics/calculateSupplementalRawAgreement.js +60 -0
- package/dist/src/evaluation/stageContextMetrics/calculateTruncationClassification.js +144 -0
- package/dist/src/evaluation/stageContextMetrics/evaluateProducerReadinessBridge.js +198 -0
- package/dist/src/evaluation/stageContextMetrics/index.js +11 -0
- package/dist/src/evaluation/stageContextMetrics/producerReadinessMetricTypes.js +1 -0
- package/dist/src/evaluation/stageContextMetrics/runIntegrityAgreementTypes.js +1 -0
- package/dist/src/evaluation/stageContextSelectors/contextArtifactConsistency.js +17 -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 +8 -0
- package/dist/src/evaluation/upstreamArtifacts/orchestratorContextReadinessResultV1.js +247 -0
- package/dist/src/evaluation/upstreamArtifacts/orchestratorRunIntegrityV1.js +33 -0
- package/dist/src/evaluation/upstreamArtifacts/readImplementationContextPacketV1.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/readImplementationContextRetrievalReportV1.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/readOrchestratorRunIntegrityV1.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/readSupplementalContextTextFile.js +29 -0
- package/dist/src/evaluation/upstreamArtifacts/readTestContextPacketV1.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/readTestContextRetrievalReportV1.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/supplementalContextTextParser.js +75 -0
- package/dist/src/evaluation/upstreamArtifacts/supplementalContextTypes.js +152 -0
- package/dist/src/evaluation/upstreamArtifacts/validateMyDevKitContextCapsuleV1.js +59 -2
- package/dist/src/evaluation/upstreamArtifacts/validateMyDevKitRetrievalAuditRecordV1.js +15 -3
- package/dist/src/evaluation/upstreamArtifacts/validateOrchestratorRunIntegrityV1.js +177 -0
- package/dist/src/evaluation/upstreamArtifacts/validateSupplementalContextDocumentV1.js +148 -0
- package/dist/src/experiments/plugins/contextStrategyComparison/loadV043StrategyArtifacts.js +117 -6
- package/dist/src/experiments/plugins/contextStrategyComparison/runV043StageContextStrategyWithAssurance.js +18 -3
- package/dist/src/experiments/plugins/contextStrategyComparison/validateV043StrategyInput.js +17 -3
- package/dist/src/report/experiments/buildContextIntegrityReport.js +204 -0
- package/dist/src/report/experiments/buildContextStrategyComparisonV043Report.js +122 -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/report/experiments/renderContextStrategyComparisonV043Html.js +62 -0
- package/dist/src/report/experiments/renderPluginExperimentReportText.js +67 -0
- package/dist/src/securityValidation/packageChecks/requiredPackageContents.js +33 -0
- package/dist/src/securityValidation/packageChecks/runPackageChecks.js +11 -5
- package/docs/METRICS.md +111 -0
- package/package.json +5 -3
- 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-1.10.2-identity/PROVENANCE.txt +13 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit-1.10.2-identity/context-capsule.json +7874 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit-1.10.2-identity/retrieval-audit-record.json +1076 -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,212 @@
|
|
|
1
|
+
// v0.4.4 Batch 2: readiness/raw-evidence agreement. Readiness stays observed consumer
|
|
2
|
+
// output (Batch 1) -- this module only compares it against an explicit fixture-declared
|
|
3
|
+
// expectation. It never calls, imports, or reimplements contextReadiness.ts.
|
|
4
|
+
import { checkSupplementalReadinessIdentityConsistency } from "../upstreamArtifacts/index.js";
|
|
5
|
+
const READINESS_ADEQUATE_STATUSES = [
|
|
6
|
+
"context sufficient for implementation",
|
|
7
|
+
"context sufficient with listed assumptions"
|
|
8
|
+
];
|
|
9
|
+
function unavailableStructural(field, reason) {
|
|
10
|
+
return { field, expectedValue: null, observedValue: null, agreement: null, availability: "unavailable", reason };
|
|
11
|
+
}
|
|
12
|
+
export function calculateReadinessStructuralAgreement(readiness, supplementalPacket, packetSourcePath) {
|
|
13
|
+
const results = [];
|
|
14
|
+
if (readiness === undefined) {
|
|
15
|
+
results.push(unavailableStructural("canonicalRepositoryIdentity", "No readiness result was supplied."));
|
|
16
|
+
results.push(unavailableStructural("packetPath", "No readiness result was supplied."));
|
|
17
|
+
return results;
|
|
18
|
+
}
|
|
19
|
+
if (supplementalPacket === undefined) {
|
|
20
|
+
results.push(unavailableStructural("canonicalRepositoryIdentity", "No supplemental document was supplied to compare against readiness."));
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const diagnostic = checkSupplementalReadinessIdentityConsistency(supplementalPacket, readiness);
|
|
24
|
+
results.push({
|
|
25
|
+
field: "canonicalRepositoryIdentity",
|
|
26
|
+
expectedValue: supplementalPacket.indexIdentity,
|
|
27
|
+
observedValue: readiness.indexIdentity ?? null,
|
|
28
|
+
agreement: diagnostic === null,
|
|
29
|
+
availability: readiness.indexIdentity === undefined ? "unavailable" : "available",
|
|
30
|
+
reason: readiness.indexIdentity === undefined ? "The readiness result does not declare indexIdentity." : diagnostic?.message ?? null
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (packetSourcePath === undefined) {
|
|
34
|
+
results.push(unavailableStructural("packetPath", "No packet source path was supplied to compare against readiness.packetPath."));
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
results.push({
|
|
38
|
+
field: "packetPath",
|
|
39
|
+
expectedValue: packetSourcePath,
|
|
40
|
+
observedValue: readiness.packetPath,
|
|
41
|
+
agreement: packetSourcePath === readiness.packetPath,
|
|
42
|
+
availability: "available",
|
|
43
|
+
reason: null
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return results;
|
|
47
|
+
}
|
|
48
|
+
export function calculateReadinessDecisionAgreement(readiness, expectation) {
|
|
49
|
+
if (expectation === undefined) {
|
|
50
|
+
return {
|
|
51
|
+
availability: "not-applicable",
|
|
52
|
+
observedDecision: readiness?.decision ?? null,
|
|
53
|
+
allowedDecisions: null,
|
|
54
|
+
decisionAgreement: null,
|
|
55
|
+
observedClassification: readiness?.classification ?? null,
|
|
56
|
+
expectedClassification: null,
|
|
57
|
+
classificationAgreement: null,
|
|
58
|
+
observedIssueCodes: readiness?.blockingIssueCodes ?? [],
|
|
59
|
+
expectedIssueCodes: null,
|
|
60
|
+
issueCodesAgreement: null,
|
|
61
|
+
observedPrimaryIssueCode: readiness?.primaryIssue?.code ?? null,
|
|
62
|
+
expectedPrimaryIssueCode: null,
|
|
63
|
+
primaryIssueAgreement: null,
|
|
64
|
+
reason: "The expectation fixture declares no readiness expectation."
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
if (readiness === undefined) {
|
|
68
|
+
return {
|
|
69
|
+
availability: "unavailable",
|
|
70
|
+
observedDecision: null,
|
|
71
|
+
allowedDecisions: expectation.allowedDecisions ?? null,
|
|
72
|
+
decisionAgreement: null,
|
|
73
|
+
observedClassification: null,
|
|
74
|
+
expectedClassification: expectation.expectedClassification ?? null,
|
|
75
|
+
classificationAgreement: null,
|
|
76
|
+
observedIssueCodes: [],
|
|
77
|
+
expectedIssueCodes: expectation.expectedIssueCodes ?? null,
|
|
78
|
+
issueCodesAgreement: null,
|
|
79
|
+
observedPrimaryIssueCode: null,
|
|
80
|
+
expectedPrimaryIssueCode: expectation.expectedPrimaryIssueCode ?? null,
|
|
81
|
+
primaryIssueAgreement: null,
|
|
82
|
+
reason: "No readiness result was supplied."
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const decisionAgreement = expectation.allowedDecisions === undefined ? null : expectation.allowedDecisions.includes(readiness.decision);
|
|
86
|
+
const classificationAgreement = expectation.expectedClassification === undefined ? null : expectation.expectedClassification === readiness.classification;
|
|
87
|
+
const issueCodesAgreement = expectation.expectedIssueCodes === undefined
|
|
88
|
+
? null
|
|
89
|
+
: expectation.expectedIssueCodes.length === readiness.blockingIssueCodes.length &&
|
|
90
|
+
expectation.expectedIssueCodes.every((code) => readiness.blockingIssueCodes.includes(code));
|
|
91
|
+
const primaryIssueAgreement = expectation.expectedPrimaryIssueCode === undefined
|
|
92
|
+
? null
|
|
93
|
+
: expectation.expectedPrimaryIssueCode === (readiness.primaryIssue?.code ?? null);
|
|
94
|
+
return {
|
|
95
|
+
availability: "available",
|
|
96
|
+
observedDecision: readiness.decision,
|
|
97
|
+
allowedDecisions: expectation.allowedDecisions ?? null,
|
|
98
|
+
decisionAgreement,
|
|
99
|
+
observedClassification: readiness.classification,
|
|
100
|
+
expectedClassification: expectation.expectedClassification ?? null,
|
|
101
|
+
classificationAgreement,
|
|
102
|
+
observedIssueCodes: readiness.blockingIssueCodes,
|
|
103
|
+
expectedIssueCodes: expectation.expectedIssueCodes ?? null,
|
|
104
|
+
issueCodesAgreement,
|
|
105
|
+
observedPrimaryIssueCode: readiness.primaryIssue?.code ?? null,
|
|
106
|
+
expectedPrimaryIssueCode: expectation.expectedPrimaryIssueCode ?? null,
|
|
107
|
+
primaryIssueAgreement,
|
|
108
|
+
reason: null
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
export function calculateInvalidReady(readiness, expectation) {
|
|
112
|
+
if (readiness === undefined) {
|
|
113
|
+
return { availability: "unavailable", invalidReady: null, observedDecision: null, expectedBlockingDecision: false, missingExpectedIssueCodes: [], reason: "No readiness result was supplied." };
|
|
114
|
+
}
|
|
115
|
+
if (expectation === undefined) {
|
|
116
|
+
return { availability: "not-applicable", invalidReady: null, observedDecision: readiness.decision, expectedBlockingDecision: false, missingExpectedIssueCodes: [], reason: "The expectation fixture declares no readiness expectation." };
|
|
117
|
+
}
|
|
118
|
+
const expectsBlocking = (expectation.allowedDecisions !== undefined &&
|
|
119
|
+
!expectation.allowedDecisions.includes("ready") &&
|
|
120
|
+
(expectation.allowedDecisions.includes("refresh-required") || expectation.allowedDecisions.length > 0)) ||
|
|
121
|
+
(expectation.expectedIssueCodes !== undefined && expectation.expectedIssueCodes.length > 0);
|
|
122
|
+
if (!expectsBlocking) {
|
|
123
|
+
return { availability: "not-applicable", invalidReady: null, observedDecision: readiness.decision, expectedBlockingDecision: false, missingExpectedIssueCodes: [], reason: "The expectation fixture does not require blocked or refresh-required behavior." };
|
|
124
|
+
}
|
|
125
|
+
if (readiness.decision !== "ready") {
|
|
126
|
+
return { availability: "available", invalidReady: false, observedDecision: readiness.decision, expectedBlockingDecision: true, missingExpectedIssueCodes: [], reason: null };
|
|
127
|
+
}
|
|
128
|
+
const expectedCodes = expectation.expectedIssueCodes ?? [];
|
|
129
|
+
const missing = expectedCodes.filter((code) => !readiness.blockingIssueCodes.includes(code));
|
|
130
|
+
return { availability: "available", invalidReady: true, observedDecision: readiness.decision, expectedBlockingDecision: true, missingExpectedIssueCodes: missing, reason: null };
|
|
131
|
+
}
|
|
132
|
+
export function calculateValidBlocked(readiness, expectation) {
|
|
133
|
+
if (readiness === undefined) {
|
|
134
|
+
return { availability: "unavailable", validBlocked: null, validRefreshRequired: null, observedDecision: null, reason: "No readiness result was supplied." };
|
|
135
|
+
}
|
|
136
|
+
if (expectation === undefined) {
|
|
137
|
+
return { availability: "not-applicable", validBlocked: null, validRefreshRequired: null, observedDecision: readiness.decision, reason: "The expectation fixture declares no readiness expectation." };
|
|
138
|
+
}
|
|
139
|
+
if (readiness.decision !== "refresh-required") {
|
|
140
|
+
return { availability: "available", validBlocked: false, validRefreshRequired: false, observedDecision: readiness.decision, reason: null };
|
|
141
|
+
}
|
|
142
|
+
const allowsRefreshRequired = expectation.allowedDecisions === undefined || expectation.allowedDecisions.includes("refresh-required");
|
|
143
|
+
const issueCodesMatch = expectation.expectedIssueCodes === undefined ||
|
|
144
|
+
expectation.expectedIssueCodes.every((code) => readiness.blockingIssueCodes.includes(code));
|
|
145
|
+
const primaryMatches = expectation.expectedPrimaryIssueCode === undefined || expectation.expectedPrimaryIssueCode === (readiness.primaryIssue?.code ?? null);
|
|
146
|
+
const valid = allowsRefreshRequired && issueCodesMatch && primaryMatches;
|
|
147
|
+
return { availability: "available", validBlocked: valid, validRefreshRequired: valid, observedDecision: readiness.decision, reason: null };
|
|
148
|
+
}
|
|
149
|
+
// v0.4.5 Batch 2 (section 18): compares producer role adequacy (as already reconciled with
|
|
150
|
+
// condition-coverage evidence by calculateProducerConditionAgreement) against the supplied
|
|
151
|
+
// orchestrator readiness decision already accepted by the v0.4.4 bridge. This never decides
|
|
152
|
+
// what readiness "should" have been -- it only reports the observed relationship.
|
|
153
|
+
export function calculateProducerReadinessRelationship(roleAdequacyStatus, producerConditionAgreement, readiness) {
|
|
154
|
+
if (roleAdequacyStatus === undefined || readiness === undefined) {
|
|
155
|
+
return {
|
|
156
|
+
availability: "unavailable",
|
|
157
|
+
outcome: "insufficient-evidence",
|
|
158
|
+
observedRoleAdequacyStatus: roleAdequacyStatus ?? null,
|
|
159
|
+
observedReadinessDecision: readiness?.decision ?? null,
|
|
160
|
+
contradictionCodes: [],
|
|
161
|
+
reason: roleAdequacyStatus === undefined && readiness === undefined
|
|
162
|
+
? "Neither roleAdequacy.status nor a readiness result was supplied."
|
|
163
|
+
: roleAdequacyStatus === undefined
|
|
164
|
+
? "No roleAdequacy.status was supplied."
|
|
165
|
+
: "No readiness result was supplied."
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
if (producerConditionAgreement.outcome === "contradiction") {
|
|
169
|
+
return {
|
|
170
|
+
availability: "available",
|
|
171
|
+
outcome: "insufficient-evidence",
|
|
172
|
+
observedRoleAdequacyStatus: roleAdequacyStatus,
|
|
173
|
+
observedReadinessDecision: readiness.decision,
|
|
174
|
+
contradictionCodes: [],
|
|
175
|
+
reason: "Producer role-adequacy already contradicts its own condition-coverage evidence; the readiness relationship cannot be attributed to either side."
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
if (producerConditionAgreement.outcome === "unsupported-legacy-evidence" || producerConditionAgreement.outcome === "insufficient-evidence") {
|
|
179
|
+
return {
|
|
180
|
+
availability: "unavailable",
|
|
181
|
+
outcome: producerConditionAgreement.outcome,
|
|
182
|
+
observedRoleAdequacyStatus: roleAdequacyStatus,
|
|
183
|
+
observedReadinessDecision: readiness.decision,
|
|
184
|
+
contradictionCodes: [],
|
|
185
|
+
reason: producerConditionAgreement.reason
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const producerAdequate = READINESS_ADEQUATE_STATUSES.includes(roleAdequacyStatus);
|
|
189
|
+
const readinessReady = readiness.decision === "ready";
|
|
190
|
+
const contradictionCodes = [];
|
|
191
|
+
if (producerAdequate && !readinessReady)
|
|
192
|
+
contradictionCodes.push("PRODUCER_ADEQUATE_BUT_READINESS_NOT_READY");
|
|
193
|
+
if (!producerAdequate && readinessReady)
|
|
194
|
+
contradictionCodes.push("PRODUCER_INADEQUATE_BUT_READINESS_READY");
|
|
195
|
+
const outcome = contradictionCodes.length > 0 ? "contradiction" : "agreement";
|
|
196
|
+
return {
|
|
197
|
+
availability: "available",
|
|
198
|
+
outcome,
|
|
199
|
+
observedRoleAdequacyStatus: roleAdequacyStatus,
|
|
200
|
+
observedReadinessDecision: readiness.decision,
|
|
201
|
+
contradictionCodes,
|
|
202
|
+
reason: outcome === "contradiction" ? "Producer role adequacy and supplied orchestrator readiness disagree; both sides are retained without a lab-owned verdict." : null
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
export function calculateReadinessAgreementMetrics(readiness, expectation, supplementalPacket, packetSourcePath) {
|
|
206
|
+
return {
|
|
207
|
+
structuralAgreement: calculateReadinessStructuralAgreement(readiness, supplementalPacket, packetSourcePath),
|
|
208
|
+
decisionAgreement: calculateReadinessDecisionAgreement(readiness, expectation),
|
|
209
|
+
invalidReady: calculateInvalidReady(readiness, expectation),
|
|
210
|
+
validBlocked: calculateValidBlocked(readiness, expectation)
|
|
211
|
+
};
|
|
212
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
function extractRawIdentity(artifact) {
|
|
2
|
+
return {
|
|
3
|
+
projectRoot: artifact.index.projectRoot,
|
|
4
|
+
role: artifact.request.role,
|
|
5
|
+
freshnessState: artifact.freshness.state,
|
|
6
|
+
truncated: artifact.truncation.truncated,
|
|
7
|
+
requiredEvidenceLost: artifact.truncation.requiredEvidenceLost
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function truncationToYesNo(value) {
|
|
11
|
+
return value ? "yes" : "no";
|
|
12
|
+
}
|
|
13
|
+
function buildField(field, rawValue, supplementalValue, unavailableReason) {
|
|
14
|
+
if (unavailableReason !== null) {
|
|
15
|
+
return { field, rawValue, supplementalValue, agreement: null, availability: "unavailable", reason: unavailableReason };
|
|
16
|
+
}
|
|
17
|
+
return { field, rawValue, supplementalValue, agreement: rawValue === supplementalValue, availability: "available", reason: null };
|
|
18
|
+
}
|
|
19
|
+
export function calculateSupplementalRawAgreement(supplemental, raw) {
|
|
20
|
+
if (supplemental === undefined || raw === undefined) {
|
|
21
|
+
const reason = supplemental === undefined && raw === undefined
|
|
22
|
+
? "Neither a supplemental document nor a raw artifact was supplied."
|
|
23
|
+
: supplemental === undefined
|
|
24
|
+
? "No supplemental document was supplied."
|
|
25
|
+
: "No raw context-capsule or retrieval-audit artifact was supplied.";
|
|
26
|
+
const fields = [
|
|
27
|
+
buildField("canonicalRepositoryIdentity", null, supplemental?.indexIdentity ?? null, reason),
|
|
28
|
+
buildField("role", null, supplemental?.role ?? null, reason),
|
|
29
|
+
buildField("freshness", null, supplemental?.freshness ?? null, reason),
|
|
30
|
+
buildField("requiredEvidenceTruncated", null, supplemental?.requiredEvidenceTruncated ?? null, reason),
|
|
31
|
+
buildField("requiredEvidenceLost", null, supplemental?.requiredEvidenceTruncated ?? null, reason)
|
|
32
|
+
];
|
|
33
|
+
return { fields, contradictions: [], upstreamProducerParityPreserved: null };
|
|
34
|
+
}
|
|
35
|
+
const rawIdentity = extractRawIdentity(raw);
|
|
36
|
+
const fields = [];
|
|
37
|
+
fields.push(buildField("canonicalRepositoryIdentity", rawIdentity.projectRoot ?? null, supplemental.indexIdentity, rawIdentity.projectRoot === undefined ? "The raw artifact does not declare index.projectRoot." : null));
|
|
38
|
+
const roleComparable = rawIdentity.role === "implementation" || rawIdentity.role === "test-implementation";
|
|
39
|
+
fields.push(buildField("role", rawIdentity.role, supplemental.role, roleComparable ? null : `Raw role "${rawIdentity.role}" has no supplemental-document counterpart in this vocabulary.`));
|
|
40
|
+
fields.push(buildField("freshness", rawIdentity.freshnessState, supplemental.freshness, null));
|
|
41
|
+
fields.push(buildField("requiredEvidenceTruncated", truncationToYesNo(rawIdentity.truncated), supplemental.requiredEvidenceTruncated, supplemental.requiredEvidenceTruncated === "unknown"
|
|
42
|
+
? "The supplemental document declares truncation as \"unknown\", so agreement with the raw boolean cannot be determined."
|
|
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));
|
|
52
|
+
const contradictions = fields.filter((f) => f.availability === "available" && f.agreement === false);
|
|
53
|
+
return {
|
|
54
|
+
fields,
|
|
55
|
+
contradictions,
|
|
56
|
+
// A successfully read raw pair is itself the observed outcome of the frozen
|
|
57
|
+
// assertRawEvidenceParity() write-time guard; see file header. Never recomputed here.
|
|
58
|
+
upstreamProducerParityPreserved: true
|
|
59
|
+
};
|
|
60
|
+
}
|