@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
|
@@ -909,7 +909,7 @@ function validateTestInfrastructureSummary(ctx, value, fieldPath) {
|
|
|
909
909
|
}
|
|
910
910
|
function validateGroupTruncationEntry(ctx, value, fieldPath) {
|
|
911
911
|
const obj = requiredObject(ctx, value, fieldPath);
|
|
912
|
-
|
|
912
|
+
const result = {
|
|
913
913
|
groupId: requiredString(ctx, requiredField(ctx, obj, "groupId", joinFieldPath(fieldPath, "groupId")), joinFieldPath(fieldPath, "groupId")),
|
|
914
914
|
limit: requiredNullableNumber(ctx, requiredField(ctx, obj, "limit", joinFieldPath(fieldPath, "limit")), joinFieldPath(fieldPath, "limit")),
|
|
915
915
|
availableCount: requiredNonnegativeInteger(ctx, requiredField(ctx, obj, "availableCount", joinFieldPath(fieldPath, "availableCount")), joinFieldPath(fieldPath, "availableCount")),
|
|
@@ -917,6 +917,54 @@ function validateGroupTruncationEntry(ctx, value, fieldPath) {
|
|
|
917
917
|
truncated: requiredBoolean(ctx, requiredField(ctx, obj, "truncated", joinFieldPath(fieldPath, "truncated")), joinFieldPath(fieldPath, "truncated")),
|
|
918
918
|
droppedCount: requiredNonnegativeInteger(ctx, requiredField(ctx, obj, "droppedCount", joinFieldPath(fieldPath, "droppedCount")), joinFieldPath(fieldPath, "droppedCount"))
|
|
919
919
|
};
|
|
920
|
+
if (optionalField(obj, "droppedEvidenceIds") !== undefined) {
|
|
921
|
+
result.droppedEvidenceIds = requiredStringArray(ctx, obj.droppedEvidenceIds, joinFieldPath(fieldPath, "droppedEvidenceIds"));
|
|
922
|
+
}
|
|
923
|
+
if (optionalField(obj, "required") !== undefined)
|
|
924
|
+
result.required = optionalBoolean(ctx, obj.required, joinFieldPath(fieldPath, "required"));
|
|
925
|
+
if (optionalField(obj, "reservation") !== undefined)
|
|
926
|
+
result.reservation = optionalNumber(ctx, obj.reservation, joinFieldPath(fieldPath, "reservation"));
|
|
927
|
+
if (optionalField(obj, "initiallySelectedCount") !== undefined)
|
|
928
|
+
result.initiallySelectedCount = optionalNumber(ctx, obj.initiallySelectedCount, joinFieldPath(fieldPath, "initiallySelectedCount"));
|
|
929
|
+
if (optionalField(obj, "unusedReservationContributed") !== undefined)
|
|
930
|
+
result.unusedReservationContributed = optionalNumber(ctx, obj.unusedReservationContributed, joinFieldPath(fieldPath, "unusedReservationContributed"));
|
|
931
|
+
if (optionalField(obj, "borrowedCapacity") !== undefined)
|
|
932
|
+
result.borrowedCapacity = optionalNumber(ctx, obj.borrowedCapacity, joinFieldPath(fieldPath, "borrowedCapacity"));
|
|
933
|
+
if (optionalField(obj, "requiredOmittedCount") !== undefined)
|
|
934
|
+
result.requiredOmittedCount = optionalNumber(ctx, obj.requiredOmittedCount, joinFieldPath(fieldPath, "requiredOmittedCount"));
|
|
935
|
+
if (optionalField(obj, "optionalOmittedCount") !== undefined)
|
|
936
|
+
result.optionalOmittedCount = optionalNumber(ctx, obj.optionalOmittedCount, joinFieldPath(fieldPath, "optionalOmittedCount"));
|
|
937
|
+
if (optionalField(obj, "adequacyAffected") !== undefined)
|
|
938
|
+
result.adequacyAffected = optionalBoolean(ctx, obj.adequacyAffected, joinFieldPath(fieldPath, "adequacyAffected"));
|
|
939
|
+
if (optionalField(obj, "governingHardBound") !== undefined)
|
|
940
|
+
result.governingHardBound = optionalNumber(ctx, obj.governingHardBound, joinFieldPath(fieldPath, "governingHardBound"));
|
|
941
|
+
if (optionalField(obj, "aggregateCapacityUsed") !== undefined)
|
|
942
|
+
result.aggregateCapacityUsed = optionalNumber(ctx, obj.aggregateCapacityUsed, joinFieldPath(fieldPath, "aggregateCapacityUsed"));
|
|
943
|
+
if (optionalField(obj, "aggregateCapacityRemaining") !== undefined)
|
|
944
|
+
result.aggregateCapacityRemaining = optionalNumber(ctx, obj.aggregateCapacityRemaining, joinFieldPath(fieldPath, "aggregateCapacityRemaining"));
|
|
945
|
+
return result;
|
|
946
|
+
}
|
|
947
|
+
const ROLE_CONDITION_IDS = ["implementation.selected-owner", "implementation.required-contract"];
|
|
948
|
+
const ROLE_CONDITION_WITNESS_POLICIES = ["at-least-one"];
|
|
949
|
+
const ROLE_CONDITION_COVERAGE_LOSS_REASONS = ["bounded-allocation-omitted-required-witnesses"];
|
|
950
|
+
const ROLE_CONDITION_ROLES = ["architecture", "implementation", "test-implementation"];
|
|
951
|
+
export function validateRoleConditionCoverage(ctx, value, fieldPath) {
|
|
952
|
+
const obj = requiredObject(ctx, value, fieldPath);
|
|
953
|
+
return {
|
|
954
|
+
conditionId: requiredLiteral(ctx, requiredField(ctx, obj, "conditionId", joinFieldPath(fieldPath, "conditionId")), joinFieldPath(fieldPath, "conditionId"), ROLE_CONDITION_IDS),
|
|
955
|
+
role: requiredLiteral(ctx, requiredField(ctx, obj, "role", joinFieldPath(fieldPath, "role")), joinFieldPath(fieldPath, "role"), ROLE_CONDITION_ROLES),
|
|
956
|
+
required: requiredBoolean(ctx, requiredField(ctx, obj, "required", joinFieldPath(fieldPath, "required")), joinFieldPath(fieldPath, "required")),
|
|
957
|
+
evidenceGroupIds: requiredStringArray(ctx, requiredField(ctx, obj, "evidenceGroupIds", joinFieldPath(fieldPath, "evidenceGroupIds")), joinFieldPath(fieldPath, "evidenceGroupIds")),
|
|
958
|
+
witnessPolicy: requiredLiteral(ctx, requiredField(ctx, obj, "witnessPolicy", joinFieldPath(fieldPath, "witnessPolicy")), joinFieldPath(fieldPath, "witnessPolicy"), ROLE_CONDITION_WITNESS_POLICIES),
|
|
959
|
+
requiredWitnessCount: requiredNonnegativeInteger(ctx, requiredField(ctx, obj, "requiredWitnessCount", joinFieldPath(fieldPath, "requiredWitnessCount")), joinFieldPath(fieldPath, "requiredWitnessCount")),
|
|
960
|
+
availableWitnessCount: requiredNonnegativeInteger(ctx, requiredField(ctx, obj, "availableWitnessCount", joinFieldPath(fieldPath, "availableWitnessCount")), joinFieldPath(fieldPath, "availableWitnessCount")),
|
|
961
|
+
retainedWitnessCount: requiredNonnegativeInteger(ctx, requiredField(ctx, obj, "retainedWitnessCount", joinFieldPath(fieldPath, "retainedWitnessCount")), joinFieldPath(fieldPath, "retainedWitnessCount")),
|
|
962
|
+
retainedWitnessIds: requiredStringArray(ctx, requiredField(ctx, obj, "retainedWitnessIds", joinFieldPath(fieldPath, "retainedWitnessIds")), joinFieldPath(fieldPath, "retainedWitnessIds")),
|
|
963
|
+
conditionSatisfied: requiredBoolean(ctx, requiredField(ctx, obj, "conditionSatisfied", joinFieldPath(fieldPath, "conditionSatisfied")), joinFieldPath(fieldPath, "conditionSatisfied")),
|
|
964
|
+
lostRequiredCondition: requiredBoolean(ctx, requiredField(ctx, obj, "lostRequiredCondition", joinFieldPath(fieldPath, "lostRequiredCondition")), joinFieldPath(fieldPath, "lostRequiredCondition")),
|
|
965
|
+
lossReason: requiredNullableLiteral(ctx, requiredField(ctx, obj, "lossReason", joinFieldPath(fieldPath, "lossReason")), joinFieldPath(fieldPath, "lossReason"), ROLE_CONDITION_COVERAGE_LOSS_REASONS),
|
|
966
|
+
evaluationOrder: requiredNumber(ctx, requiredField(ctx, obj, "evaluationOrder", joinFieldPath(fieldPath, "evaluationOrder")), joinFieldPath(fieldPath, "evaluationOrder"))
|
|
967
|
+
};
|
|
920
968
|
}
|
|
921
969
|
export function validateProvenanceRecord(ctx, value, fieldPath) {
|
|
922
970
|
const obj = requiredObject(ctx, value, fieldPath);
|
|
@@ -1040,11 +1088,15 @@ function validateCapsuleTruncationRecord(ctx, value, fieldPath) {
|
|
|
1040
1088
|
}
|
|
1041
1089
|
export function validateTruncationSummary(ctx, value, fieldPath) {
|
|
1042
1090
|
const obj = requiredObject(ctx, value, fieldPath);
|
|
1043
|
-
|
|
1091
|
+
const result = {
|
|
1044
1092
|
truncated: requiredBoolean(ctx, requiredField(ctx, obj, "truncated", joinFieldPath(fieldPath, "truncated")), joinFieldPath(fieldPath, "truncated")),
|
|
1045
1093
|
records: requiredArray(ctx, requiredField(ctx, obj, "records", joinFieldPath(fieldPath, "records")), joinFieldPath(fieldPath, "records")).map((item, i) => validateCapsuleTruncationRecord(ctx, item, arrayFieldPath(joinFieldPath(fieldPath, "records"), i))),
|
|
1046
1094
|
warnings: requiredStringArray(ctx, requiredField(ctx, obj, "warnings", joinFieldPath(fieldPath, "warnings")), joinFieldPath(fieldPath, "warnings"))
|
|
1047
1095
|
};
|
|
1096
|
+
if (optionalField(obj, "requiredEvidenceLost") !== undefined) {
|
|
1097
|
+
result.requiredEvidenceLost = optionalBoolean(ctx, obj.requiredEvidenceLost, joinFieldPath(fieldPath, "requiredEvidenceLost"));
|
|
1098
|
+
}
|
|
1099
|
+
return result;
|
|
1048
1100
|
}
|
|
1049
1101
|
function validateFullFileFallbackRecord(ctx, value, fieldPath) {
|
|
1050
1102
|
const obj = requiredObject(ctx, value, fieldPath);
|
|
@@ -1178,6 +1230,11 @@ export function validateMyDevKitContextCapsuleV1(value, sourcePath) {
|
|
|
1178
1230
|
testInfrastructure: validateTestInfrastructureSummary(ctx, requiredField(ctx, value, "testInfrastructure", "testInfrastructure"), "testInfrastructure"),
|
|
1179
1231
|
unresolvedItems: requiredArray(ctx, requiredField(ctx, value, "unresolvedItems", "unresolvedItems"), "unresolvedItems").map((item, i) => validateUnresolvedEvidenceItem(ctx, item, arrayFieldPath("unresolvedItems", i))),
|
|
1180
1232
|
groupTruncation: requiredArray(ctx, requiredField(ctx, value, "groupTruncation", "groupTruncation"), "groupTruncation").map((item, i) => validateGroupTruncationEntry(ctx, item, arrayFieldPath("groupTruncation", i))),
|
|
1233
|
+
...(optionalField(value, "roleConditionCoverage") !== undefined
|
|
1234
|
+
? {
|
|
1235
|
+
roleConditionCoverage: requiredArray(ctx, value.roleConditionCoverage, "roleConditionCoverage").map((item, i) => validateRoleConditionCoverage(ctx, item, arrayFieldPath("roleConditionCoverage", i)))
|
|
1236
|
+
}
|
|
1237
|
+
: {}),
|
|
1181
1238
|
responsibilityMappings: validateResponsibilityMappingSummary(ctx, requiredField(ctx, value, "responsibilityMappings", "responsibilityMappings"), "responsibilityMappings"),
|
|
1182
1239
|
roleAdequacy: validateRoleAdequacyStatement(ctx, requiredField(ctx, value, "roleAdequacy", "roleAdequacy"), "roleAdequacy"),
|
|
1183
1240
|
freshness: validateFreshnessSummary(ctx, requiredField(ctx, value, "freshness", "freshness"), "freshness"),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseSupportedMajorOneSchemaVersion } from "./schemaVersion.js";
|
|
2
|
-
import { ArtifactValidationError, arrayFieldPath, joinFieldPath, requiredArray, requiredField, requiredLiteral, requiredObject, requiredRecord, requiredScalarLike, requiredString, requiredStringArray } from "./runtimeValidation.js";
|
|
3
|
-
import { validateBudgetSummary, validateContextAdequacyStatement, validateContextCapsuleRequest, validateFreshnessSummary, validateFullFileFallbackSummary, validateProvenanceRecord, validateResponsibilityMappingSummary, validateRoleAdequacyStatement, validateRoleContextSummary, validateTruncationSummary } from "./validateMyDevKitContextCapsuleV1.js";
|
|
2
|
+
import { ArtifactValidationError, arrayFieldPath, joinFieldPath, optionalField, optionalString, requiredArray, requiredField, requiredLiteral, requiredObject, requiredRecord, requiredScalarLike, requiredString, requiredStringArray } from "./runtimeValidation.js";
|
|
3
|
+
import { validateBudgetSummary, validateContextAdequacyStatement, validateContextCapsuleRequest, validateFreshnessSummary, validateFullFileFallbackSummary, validateProvenanceRecord, validateResponsibilityMappingSummary, validateRoleAdequacyStatement, validateRoleConditionCoverage, validateRoleContextSummary, validateTruncationSummary } from "./validateMyDevKitContextCapsuleV1.js";
|
|
4
4
|
const ARTIFACT_KIND = "my-dev-kit-retrieval-audit-record-v1";
|
|
5
5
|
const AUDIT_STEP_STATUSES = ["ok", "skipped", "failed"];
|
|
6
6
|
function validateContextCapsuleTool(ctx, value, fieldPath) {
|
|
@@ -12,10 +12,17 @@ function validateContextCapsuleTool(ctx, value, fieldPath) {
|
|
|
12
12
|
}
|
|
13
13
|
function validateRetrievalAuditRecordIndex(ctx, value, fieldPath) {
|
|
14
14
|
const obj = requiredObject(ctx, value, fieldPath);
|
|
15
|
-
|
|
15
|
+
const result = {
|
|
16
16
|
indexPath: requiredString(ctx, requiredField(ctx, obj, "indexPath", joinFieldPath(fieldPath, "indexPath")), joinFieldPath(fieldPath, "indexPath")),
|
|
17
17
|
manifestPath: requiredString(ctx, requiredField(ctx, obj, "manifestPath", joinFieldPath(fieldPath, "manifestPath")), joinFieldPath(fieldPath, "manifestPath"))
|
|
18
18
|
};
|
|
19
|
+
if (optionalField(obj, "manifestSchemaVersion") !== undefined) {
|
|
20
|
+
result.manifestSchemaVersion = optionalString(ctx, obj.manifestSchemaVersion, joinFieldPath(fieldPath, "manifestSchemaVersion"));
|
|
21
|
+
}
|
|
22
|
+
if (optionalField(obj, "projectRoot") !== undefined) {
|
|
23
|
+
result.projectRoot = optionalString(ctx, obj.projectRoot, joinFieldPath(fieldPath, "projectRoot"));
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
19
26
|
}
|
|
20
27
|
function validateAuditStepRecord(ctx, value, fieldPath) {
|
|
21
28
|
const obj = requiredRecord(ctx, value, fieldPath);
|
|
@@ -76,6 +83,11 @@ export function validateMyDevKitRetrievalAuditRecordV1(value, sourcePath) {
|
|
|
76
83
|
contextAdequacy: validateContextAdequacyStatement(ctx, requiredField(ctx, value, "contextAdequacy", "contextAdequacy"), "contextAdequacy"),
|
|
77
84
|
roleContext: validateRoleContextSummary(ctx, requiredField(ctx, value, "roleContext", "roleContext"), "roleContext"),
|
|
78
85
|
responsibilityMappings: validateResponsibilityMappingSummary(ctx, requiredField(ctx, value, "responsibilityMappings", "responsibilityMappings"), "responsibilityMappings"),
|
|
86
|
+
...(optionalField(value, "roleConditionCoverage") !== undefined
|
|
87
|
+
? {
|
|
88
|
+
roleConditionCoverage: requiredArray(ctx, value.roleConditionCoverage, "roleConditionCoverage").map((item, i) => validateRoleConditionCoverage(ctx, item, arrayFieldPath("roleConditionCoverage", i)))
|
|
89
|
+
}
|
|
90
|
+
: {}),
|
|
79
91
|
roleAdequacy: validateRoleAdequacyStatement(ctx, requiredField(ctx, value, "roleAdequacy", "roleAdequacy"), "roleAdequacy"),
|
|
80
92
|
freshness: validateFreshnessSummary(ctx, requiredField(ctx, value, "freshness", "freshness"), "freshness"),
|
|
81
93
|
budget: validateBudgetSummary(ctx, requiredField(ctx, value, "budget", "budget"), "budget"),
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { parseSupportedMajorOneSchemaVersion } from "./schemaVersion.js";
|
|
2
|
+
import { ArtifactValidationError, arrayFieldPath, joinFieldPath, optionalField, optionalString, requiredArray, requiredBoolean, requiredField, requiredLiteral, requiredNullableLiteral, requiredNullableString, requiredObject, requiredString, requiredStringArray } from "./runtimeValidation.js";
|
|
3
|
+
import { validateOrchestratorContextReadinessResultV1 } from "./orchestratorContextReadinessResultV1.js";
|
|
4
|
+
import { ARTIFACT_LIFECYCLE_STATES, CONTEXT_SENSITIVE_STAGE_NAMES, CORRECTABLE_STAGES, JUDGE_VERDICT_PARSE_STATUSES, JUDGE_VERDICTS, MANUAL_ARTIFACT_LIFECYCLE_STATES, ROUTE_STATUSES, RUN_INTEGRITY_READINESS_CLASSIFICATIONS } from "./orchestratorRunIntegrityV1.js";
|
|
5
|
+
const ARTIFACT_KIND = "orchestrator-run-integrity-evidence-v1";
|
|
6
|
+
const EXPECTED_JUDGE_VERDICTS = ["PASS", "NEED_CONTEXT"];
|
|
7
|
+
const APPLICABLE_CONTEXT_KINDS = ["implementation", "test"];
|
|
8
|
+
function validateContextReadinessNested(ctx, value, fieldPath) {
|
|
9
|
+
const result = validateOrchestratorContextReadinessResultV1(value, `${ctx.sourcePath}#${fieldPath}`);
|
|
10
|
+
if (!result.ok) {
|
|
11
|
+
throw new ArtifactValidationError({
|
|
12
|
+
ok: false,
|
|
13
|
+
artifactKind: ctx.artifactKind,
|
|
14
|
+
sourcePath: ctx.sourcePath,
|
|
15
|
+
code: result.code,
|
|
16
|
+
message: `Nested readiness field "${fieldPath}" is invalid: ${result.message}`,
|
|
17
|
+
fieldPath,
|
|
18
|
+
expected: result.expected,
|
|
19
|
+
actual: result.actual
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return result.artifact;
|
|
23
|
+
}
|
|
24
|
+
function validateCorrectionRouteResult(ctx, value, fieldPath) {
|
|
25
|
+
const obj = requiredObject(ctx, value, fieldPath);
|
|
26
|
+
return {
|
|
27
|
+
verdict: requiredNullableLiteral(ctx, requiredField(ctx, obj, "verdict", joinFieldPath(fieldPath, "verdict")), joinFieldPath(fieldPath, "verdict"), JUDGE_VERDICTS),
|
|
28
|
+
recommendedStage: requiredNullableString(ctx, requiredField(ctx, obj, "recommendedStage", joinFieldPath(fieldPath, "recommendedStage")), joinFieldPath(fieldPath, "recommendedStage")),
|
|
29
|
+
routedStage: requiredNullableLiteral(ctx, requiredField(ctx, obj, "routedStage", joinFieldPath(fieldPath, "routedStage")), joinFieldPath(fieldPath, "routedStage"), CORRECTABLE_STAGES),
|
|
30
|
+
routeStatus: requiredLiteral(ctx, requiredField(ctx, obj, "routeStatus", joinFieldPath(fieldPath, "routeStatus")), joinFieldPath(fieldPath, "routeStatus"), ROUTE_STATUSES),
|
|
31
|
+
warnings: requiredStringArray(ctx, requiredField(ctx, obj, "warnings", joinFieldPath(fieldPath, "warnings")), joinFieldPath(fieldPath, "warnings")),
|
|
32
|
+
errors: requiredStringArray(ctx, requiredField(ctx, obj, "errors", joinFieldPath(fieldPath, "errors")), joinFieldPath(fieldPath, "errors")),
|
|
33
|
+
isBlocked: requiredBoolean(ctx, requiredField(ctx, obj, "isBlocked", joinFieldPath(fieldPath, "isBlocked")), joinFieldPath(fieldPath, "isBlocked")),
|
|
34
|
+
strictFail: requiredBoolean(ctx, requiredField(ctx, obj, "strictFail", joinFieldPath(fieldPath, "strictFail")), joinFieldPath(fieldPath, "strictFail"))
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function validateGate(ctx, value, fieldPath) {
|
|
38
|
+
const obj = requiredObject(ctx, value, fieldPath);
|
|
39
|
+
const result = {
|
|
40
|
+
schemaVersion: requiredLiteral(ctx, requiredField(ctx, obj, "schemaVersion", joinFieldPath(fieldPath, "schemaVersion")), joinFieldPath(fieldPath, "schemaVersion"), ["1.0.0"]),
|
|
41
|
+
mode: requiredString(ctx, requiredField(ctx, obj, "mode", joinFieldPath(fieldPath, "mode")), joinFieldPath(fieldPath, "mode")),
|
|
42
|
+
contextRequired: requiredBoolean(ctx, requiredField(ctx, obj, "contextRequired", joinFieldPath(fieldPath, "contextRequired")), joinFieldPath(fieldPath, "contextRequired")),
|
|
43
|
+
applicableContextKinds: requiredArray(ctx, requiredField(ctx, obj, "applicableContextKinds", joinFieldPath(fieldPath, "applicableContextKinds")), joinFieldPath(fieldPath, "applicableContextKinds")).map((item, i) => requiredLiteral(ctx, item, arrayFieldPath(joinFieldPath(fieldPath, "applicableContextKinds"), i), APPLICABLE_CONTEXT_KINDS)),
|
|
44
|
+
contextReady: requiredBoolean(ctx, requiredField(ctx, obj, "contextReady", joinFieldPath(fieldPath, "contextReady")), joinFieldPath(fieldPath, "contextReady")),
|
|
45
|
+
readinessClassification: requiredLiteral(ctx, requiredField(ctx, obj, "readinessClassification", joinFieldPath(fieldPath, "readinessClassification")), joinFieldPath(fieldPath, "readinessClassification"), RUN_INTEGRITY_READINESS_CLASSIFICATIONS),
|
|
46
|
+
blockedStageNames: requiredArray(ctx, requiredField(ctx, obj, "blockedStageNames", joinFieldPath(fieldPath, "blockedStageNames")), joinFieldPath(fieldPath, "blockedStageNames")).map((item, i) => requiredLiteral(ctx, item, arrayFieldPath(joinFieldPath(fieldPath, "blockedStageNames"), i), CONTEXT_SENSITIVE_STAGE_NAMES)),
|
|
47
|
+
blockingCodes: requiredStringArray(ctx, requiredField(ctx, obj, "blockingCodes", joinFieldPath(fieldPath, "blockingCodes")), joinFieldPath(fieldPath, "blockingCodes")),
|
|
48
|
+
recommendedCorrectionStage: requiredNullableString(ctx, requiredField(ctx, obj, "recommendedCorrectionStage", joinFieldPath(fieldPath, "recommendedCorrectionStage")), joinFieldPath(fieldPath, "recommendedCorrectionStage")),
|
|
49
|
+
expectedJudgeVerdict: requiredLiteral(ctx, requiredField(ctx, obj, "expectedJudgeVerdict", joinFieldPath(fieldPath, "expectedJudgeVerdict")), joinFieldPath(fieldPath, "expectedJudgeVerdict"), EXPECTED_JUDGE_VERDICTS),
|
|
50
|
+
warnings: requiredStringArray(ctx, requiredField(ctx, obj, "warnings", joinFieldPath(fieldPath, "warnings")), joinFieldPath(fieldPath, "warnings"))
|
|
51
|
+
};
|
|
52
|
+
if (optionalField(obj, "implementationContext") !== undefined) {
|
|
53
|
+
result.implementationContext = validateContextReadinessNested(ctx, obj.implementationContext, joinFieldPath(fieldPath, "implementationContext"));
|
|
54
|
+
}
|
|
55
|
+
if (optionalField(obj, "testContext") !== undefined) {
|
|
56
|
+
result.testContext = validateContextReadinessNested(ctx, obj.testContext, joinFieldPath(fieldPath, "testContext"));
|
|
57
|
+
}
|
|
58
|
+
if (optionalField(obj, "primaryBlocker") !== undefined) {
|
|
59
|
+
// primaryBlocker reuses ContextReadinessBlockerSummary's exact shape (owned by
|
|
60
|
+
// orchestratorContextReadinessResultV1.ts's blockerSummary field); walked structurally
|
|
61
|
+
// here rather than re-validated through a second nested-artifact call, since it is not
|
|
62
|
+
// itself a standalone readiness artifact.
|
|
63
|
+
const blockerObj = requiredObject(ctx, obj.primaryBlocker, joinFieldPath(fieldPath, "primaryBlocker"));
|
|
64
|
+
result.primaryBlocker = blockerObj;
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
function validateJudgeIntegrity(ctx, value, fieldPath) {
|
|
69
|
+
const obj = requiredObject(ctx, value, fieldPath);
|
|
70
|
+
const result = {
|
|
71
|
+
schemaVersion: requiredLiteral(ctx, requiredField(ctx, obj, "schemaVersion", joinFieldPath(fieldPath, "schemaVersion")), joinFieldPath(fieldPath, "schemaVersion"), ["1.0.0"]),
|
|
72
|
+
judgeArtifactPresent: requiredBoolean(ctx, requiredField(ctx, obj, "judgeArtifactPresent", joinFieldPath(fieldPath, "judgeArtifactPresent")), joinFieldPath(fieldPath, "judgeArtifactPresent")),
|
|
73
|
+
judgeVerdictParseStatus: requiredLiteral(ctx, requiredField(ctx, obj, "judgeVerdictParseStatus", joinFieldPath(fieldPath, "judgeVerdictParseStatus")), joinFieldPath(fieldPath, "judgeVerdictParseStatus"), JUDGE_VERDICT_PARSE_STATUSES),
|
|
74
|
+
authoredJudgeVerdict: requiredNullableLiteral(ctx, requiredField(ctx, obj, "authoredJudgeVerdict", joinFieldPath(fieldPath, "authoredJudgeVerdict")), joinFieldPath(fieldPath, "authoredJudgeVerdict"), JUDGE_VERDICTS),
|
|
75
|
+
expectedJudgeVerdict: requiredLiteral(ctx, requiredField(ctx, obj, "expectedJudgeVerdict", joinFieldPath(fieldPath, "expectedJudgeVerdict")), joinFieldPath(fieldPath, "expectedJudgeVerdict"), EXPECTED_JUDGE_VERDICTS),
|
|
76
|
+
judgeVerdictMatchesExpected: requiredBoolean(ctx, requiredField(ctx, obj, "judgeVerdictMatchesExpected", joinFieldPath(fieldPath, "judgeVerdictMatchesExpected")), joinFieldPath(fieldPath, "judgeVerdictMatchesExpected")),
|
|
77
|
+
judgeVerdictAccepted: requiredBoolean(ctx, requiredField(ctx, obj, "judgeVerdictAccepted", joinFieldPath(fieldPath, "judgeVerdictAccepted")), joinFieldPath(fieldPath, "judgeVerdictAccepted")),
|
|
78
|
+
correctionRequired: requiredBoolean(ctx, requiredField(ctx, obj, "correctionRequired", joinFieldPath(fieldPath, "correctionRequired")), joinFieldPath(fieldPath, "correctionRequired")),
|
|
79
|
+
correctionBlocked: requiredBoolean(ctx, requiredField(ctx, obj, "correctionBlocked", joinFieldPath(fieldPath, "correctionBlocked")), joinFieldPath(fieldPath, "correctionBlocked")),
|
|
80
|
+
acceptedCorrectionStage: requiredNullableString(ctx, requiredField(ctx, obj, "acceptedCorrectionStage", joinFieldPath(fieldPath, "acceptedCorrectionStage")), joinFieldPath(fieldPath, "acceptedCorrectionStage")),
|
|
81
|
+
finalReportEligible: requiredBoolean(ctx, requiredField(ctx, obj, "finalReportEligible", joinFieldPath(fieldPath, "finalReportEligible")), joinFieldPath(fieldPath, "finalReportEligible")),
|
|
82
|
+
blockingCodes: requiredStringArray(ctx, requiredField(ctx, obj, "blockingCodes", joinFieldPath(fieldPath, "blockingCodes")), joinFieldPath(fieldPath, "blockingCodes")),
|
|
83
|
+
acceptedCorrectionRoute: (() => {
|
|
84
|
+
const routeValue = requiredField(ctx, obj, "acceptedCorrectionRoute", joinFieldPath(fieldPath, "acceptedCorrectionRoute"));
|
|
85
|
+
return routeValue === null ? null : validateCorrectionRouteResult(ctx, routeValue, joinFieldPath(fieldPath, "acceptedCorrectionRoute"));
|
|
86
|
+
})()
|
|
87
|
+
};
|
|
88
|
+
if (optionalField(obj, "primaryReason") !== undefined) {
|
|
89
|
+
result.primaryReason = optionalString(ctx, obj.primaryReason, joinFieldPath(fieldPath, "primaryReason"));
|
|
90
|
+
}
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
function validateFinalReportEligibility(ctx, value, fieldPath) {
|
|
94
|
+
const obj = requiredObject(ctx, value, fieldPath);
|
|
95
|
+
const result = {
|
|
96
|
+
eligible: requiredBoolean(ctx, requiredField(ctx, obj, "eligible", joinFieldPath(fieldPath, "eligible")), joinFieldPath(fieldPath, "eligible")),
|
|
97
|
+
contextReady: requiredBoolean(ctx, requiredField(ctx, obj, "contextReady", joinFieldPath(fieldPath, "contextReady")), joinFieldPath(fieldPath, "contextReady")),
|
|
98
|
+
priorArtifactsValid: requiredBoolean(ctx, requiredField(ctx, obj, "priorArtifactsValid", joinFieldPath(fieldPath, "priorArtifactsValid")), joinFieldPath(fieldPath, "priorArtifactsValid")),
|
|
99
|
+
judgeIntegrity: validateJudgeIntegrity(ctx, requiredField(ctx, obj, "judgeIntegrity", joinFieldPath(fieldPath, "judgeIntegrity")), joinFieldPath(fieldPath, "judgeIntegrity")),
|
|
100
|
+
blockingCodes: requiredStringArray(ctx, requiredField(ctx, obj, "blockingCodes", joinFieldPath(fieldPath, "blockingCodes")), joinFieldPath(fieldPath, "blockingCodes"))
|
|
101
|
+
};
|
|
102
|
+
if (optionalField(obj, "primaryReason") !== undefined) {
|
|
103
|
+
result.primaryReason = optionalString(ctx, obj.primaryReason, joinFieldPath(fieldPath, "primaryReason"));
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
function validateArtifactStateRecord(ctx, value, fieldPath) {
|
|
108
|
+
const obj = requiredObject(ctx, value, fieldPath);
|
|
109
|
+
const result = {
|
|
110
|
+
state: requiredLiteral(ctx, requiredField(ctx, obj, "state", joinFieldPath(fieldPath, "state")), joinFieldPath(fieldPath, "state"), MANUAL_ARTIFACT_LIFECYCLE_STATES),
|
|
111
|
+
updatedAt: requiredString(ctx, requiredField(ctx, obj, "updatedAt", joinFieldPath(fieldPath, "updatedAt")), joinFieldPath(fieldPath, "updatedAt"))
|
|
112
|
+
};
|
|
113
|
+
if (optionalField(obj, "reason") !== undefined)
|
|
114
|
+
result.reason = optionalString(ctx, obj.reason, joinFieldPath(fieldPath, "reason"));
|
|
115
|
+
if (optionalField(obj, "source") !== undefined)
|
|
116
|
+
result.source = optionalString(ctx, obj.source, joinFieldPath(fieldPath, "source"));
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
function validateLifecycleEntry(ctx, value, fieldPath) {
|
|
120
|
+
const obj = requiredObject(ctx, value, fieldPath);
|
|
121
|
+
const manualRecordValue = requiredField(ctx, obj, "manualRecord", joinFieldPath(fieldPath, "manualRecord"));
|
|
122
|
+
const result = {
|
|
123
|
+
artifactFile: requiredString(ctx, requiredField(ctx, obj, "artifactFile", joinFieldPath(fieldPath, "artifactFile")), joinFieldPath(fieldPath, "artifactFile")),
|
|
124
|
+
stageName: requiredString(ctx, requiredField(ctx, obj, "stageName", joinFieldPath(fieldPath, "stageName")), joinFieldPath(fieldPath, "stageName")),
|
|
125
|
+
fileExists: requiredBoolean(ctx, requiredField(ctx, obj, "fileExists", joinFieldPath(fieldPath, "fileExists")), joinFieldPath(fieldPath, "fileExists")),
|
|
126
|
+
manualRecord: manualRecordValue === null ? null : validateArtifactStateRecord(ctx, manualRecordValue, joinFieldPath(fieldPath, "manualRecord")),
|
|
127
|
+
resolvedState: requiredLiteral(ctx, requiredField(ctx, obj, "resolvedState", joinFieldPath(fieldPath, "resolvedState")), joinFieldPath(fieldPath, "resolvedState"), ARTIFACT_LIFECYCLE_STATES)
|
|
128
|
+
};
|
|
129
|
+
if (optionalField(obj, "blockingReason") !== undefined) {
|
|
130
|
+
result.blockingReason = optionalString(ctx, obj.blockingReason, joinFieldPath(fieldPath, "blockingReason"));
|
|
131
|
+
}
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
export function validateOrchestratorRunIntegrityEvidenceV1(value, sourcePath) {
|
|
135
|
+
const ctx = { artifactKind: ARTIFACT_KIND, sourcePath };
|
|
136
|
+
try {
|
|
137
|
+
const schemaVersionResult = parseSupportedMajorOneSchemaVersion(requiredField(ctx, value, "schemaVersion", "schemaVersion"), ARTIFACT_KIND, sourcePath);
|
|
138
|
+
if ("ok" in schemaVersionResult)
|
|
139
|
+
return schemaVersionResult;
|
|
140
|
+
const evidence = {
|
|
141
|
+
schemaVersion: requiredString(ctx, value.schemaVersion, "schemaVersion"),
|
|
142
|
+
runFolder: requiredString(ctx, requiredField(ctx, value, "runFolder", "runFolder"), "runFolder"),
|
|
143
|
+
gate: validateGate(ctx, requiredField(ctx, value, "gate", "gate"), "gate"),
|
|
144
|
+
lifecycle: requiredArray(ctx, requiredField(ctx, value, "lifecycle", "lifecycle"), "lifecycle").map((item, i) => validateLifecycleEntry(ctx, item, arrayFieldPath("lifecycle", i)))
|
|
145
|
+
};
|
|
146
|
+
if (optionalField(value, "judgeIntegrity") !== undefined) {
|
|
147
|
+
evidence.judgeIntegrity = validateJudgeIntegrity(ctx, value.judgeIntegrity, "judgeIntegrity");
|
|
148
|
+
}
|
|
149
|
+
if (optionalField(value, "finalReportEligibility") !== undefined) {
|
|
150
|
+
evidence.finalReportEligibility = validateFinalReportEligibility(ctx, value.finalReportEligibility, "finalReportEligibility");
|
|
151
|
+
}
|
|
152
|
+
if (optionalField(value, "finalArtifactPresent") !== undefined) {
|
|
153
|
+
evidence.finalArtifactPresent = requiredBoolean(ctx, value.finalArtifactPresent, "finalArtifactPresent");
|
|
154
|
+
}
|
|
155
|
+
if (optionalField(value, "finalArtifactVerdict") !== undefined) {
|
|
156
|
+
evidence.finalArtifactVerdict = requiredNullableLiteral(ctx, value.finalArtifactVerdict, "finalArtifactVerdict", JUDGE_VERDICTS);
|
|
157
|
+
}
|
|
158
|
+
// Per the exact-mirror contract, the returned artifact is always the original parsed
|
|
159
|
+
// reference, not a rebuilt object. The construction above exists only to walk and
|
|
160
|
+
// type-check every field.
|
|
161
|
+
void evidence;
|
|
162
|
+
return {
|
|
163
|
+
ok: true,
|
|
164
|
+
artifactKind: ARTIFACT_KIND,
|
|
165
|
+
sourcePath,
|
|
166
|
+
schemaVersion: value.schemaVersion,
|
|
167
|
+
schemaMajor: 1,
|
|
168
|
+
artifact: value,
|
|
169
|
+
rawArtifact: value
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
if (error instanceof ArtifactValidationError)
|
|
174
|
+
return error.failure;
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { makeFailure } from "./runtimeValidation.js";
|
|
2
|
+
import { parseSupplementalContextText } from "./supplementalContextTextParser.js";
|
|
3
|
+
import { REQUIRED_METADATA_BY_DOCUMENT_KIND, REQUIRED_SECTIONS_BY_DOCUMENT_KIND, ROLE_BY_DOCUMENT_KIND, SUPPLEMENTAL_CONTEXT_PACKET_SCHEMA_SUPPORTED_MAJOR, SUPPLEMENTAL_CONTEXT_RETRIEVAL_REPORT_SCHEMA_SUPPORTED_MAJOR, VALID_ADEQUACY_VALUES, VALID_DECLARED_STATUSES, VALID_FRESHNESS_VALUES, VALID_REPOSITORY_SCOPES, VALID_TRUNCATION_VALUES, isRetrievalReportKind, isTestKind } from "./supplementalContextTypes.js";
|
|
4
|
+
const SCHEMA_VERSION_PATTERN = /^[0-9]+\.[0-9]+\.[0-9]+$/;
|
|
5
|
+
function supportedMajorForKind(kind) {
|
|
6
|
+
return isRetrievalReportKind(kind)
|
|
7
|
+
? SUPPLEMENTAL_CONTEXT_RETRIEVAL_REPORT_SCHEMA_SUPPORTED_MAJOR
|
|
8
|
+
: SUPPLEMENTAL_CONTEXT_PACKET_SCHEMA_SUPPORTED_MAJOR;
|
|
9
|
+
}
|
|
10
|
+
function literalOrFail(artifactKind, sourcePath, fieldPath, value, allowed, errorCode = "INVALID_LITERAL_VALUE") {
|
|
11
|
+
if (allowed.includes(value))
|
|
12
|
+
return value;
|
|
13
|
+
return {
|
|
14
|
+
ok: false,
|
|
15
|
+
artifactKind,
|
|
16
|
+
sourcePath,
|
|
17
|
+
code: errorCode,
|
|
18
|
+
message: `Field "${fieldPath}" in artifact "${artifactKind}" at "${sourcePath}" has invalid value "${value}". Expected one of: ${allowed.join(", ")}.`,
|
|
19
|
+
fieldPath,
|
|
20
|
+
expected: allowed.join(" | "),
|
|
21
|
+
actual: value
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function isFailure(value) {
|
|
25
|
+
return typeof value === "object" && value !== null && value.ok === false;
|
|
26
|
+
}
|
|
27
|
+
export function validateSupplementalContextDocumentV1(artifactKind, expectedKind, text, sourcePath) {
|
|
28
|
+
const parsed = parseSupplementalContextText(text);
|
|
29
|
+
if (parsed.metadataOrder.length === 0 && parsed.sectionOrder.length === 0) {
|
|
30
|
+
return makeFailure(artifactKind, sourcePath, "MALFORMED_TEXT_ARTIFACT", `Artifact "${artifactKind}" at "${sourcePath}" contains no recognizable "Key: value" metadata or "## Heading" sections.`);
|
|
31
|
+
}
|
|
32
|
+
// Kind/role identity is checked before general required-metadata/section completeness so
|
|
33
|
+
// that feeding one document kind's file to another kind's reader is reported as a
|
|
34
|
+
// structural identity mismatch (DOCUMENT_KIND_MISMATCH / DOCUMENT_ROLE_MISMATCH) rather
|
|
35
|
+
// than as an incidental "missing metadata key" from the wrong kind's required-field list.
|
|
36
|
+
const declaredKind = parsed.metadata["Document kind"];
|
|
37
|
+
if (declaredKind !== expectedKind) {
|
|
38
|
+
return makeFailure(artifactKind, sourcePath, "DOCUMENT_KIND_MISMATCH", `Artifact "${artifactKind}" at "${sourcePath}" declares document kind "${declaredKind}" but this reader expects "${expectedKind}".`, "Document kind", expectedKind, declaredKind);
|
|
39
|
+
}
|
|
40
|
+
const expectedRole = ROLE_BY_DOCUMENT_KIND[expectedKind];
|
|
41
|
+
const declaredRole = parsed.metadata["Role"];
|
|
42
|
+
if (declaredRole !== expectedRole) {
|
|
43
|
+
return makeFailure(artifactKind, sourcePath, "DOCUMENT_ROLE_MISMATCH", `Artifact "${artifactKind}" at "${sourcePath}" declares role "${declaredRole}" but this reader expects "${expectedRole}".`, "Role", expectedRole, declaredRole);
|
|
44
|
+
}
|
|
45
|
+
const requiredMetadata = REQUIRED_METADATA_BY_DOCUMENT_KIND[expectedKind];
|
|
46
|
+
for (const key of requiredMetadata) {
|
|
47
|
+
if (!(key in parsed.metadata)) {
|
|
48
|
+
return makeFailure(artifactKind, sourcePath, "MISSING_REQUIRED_METADATA", `Artifact "${artifactKind}" at "${sourcePath}" is missing required metadata key "${key}".`, key, "present");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const requiredSections = REQUIRED_SECTIONS_BY_DOCUMENT_KIND[expectedKind];
|
|
52
|
+
for (const heading of requiredSections) {
|
|
53
|
+
if (!(heading in parsed.sections)) {
|
|
54
|
+
return makeFailure(artifactKind, sourcePath, "MISSING_REQUIRED_SECTION", `Artifact "${artifactKind}" at "${sourcePath}" is missing required section heading "## ${heading}".`, heading, "present");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const schemaVersion = parsed.metadata["Schema version"];
|
|
58
|
+
if (!SCHEMA_VERSION_PATTERN.test(schemaVersion)) {
|
|
59
|
+
return makeFailure(artifactKind, sourcePath, "INVALID_SCHEMA_VERSION", `Artifact "${artifactKind}" at "${sourcePath}" has an invalid "Schema version": expected strict "x.y.z" semantic version.`, "Schema version", "^[0-9]+\\.[0-9]+\\.[0-9]+$", schemaVersion);
|
|
60
|
+
}
|
|
61
|
+
const major = Number(schemaVersion.split(".")[0]);
|
|
62
|
+
const supportedMajor = supportedMajorForKind(expectedKind);
|
|
63
|
+
if (major !== supportedMajor) {
|
|
64
|
+
return makeFailure(artifactKind, sourcePath, "UNSUPPORTED_SCHEMA_MAJOR", `Artifact "${artifactKind}" at "${sourcePath}" has unsupported schema major "${major}" in "Schema version": supported major is ${supportedMajor}.`, "Schema version", String(supportedMajor), schemaVersion);
|
|
65
|
+
}
|
|
66
|
+
const status = literalOrFail(artifactKind, sourcePath, "Status", parsed.metadata["Status"], VALID_DECLARED_STATUSES, "UNKNOWN_STATUS_VALUE");
|
|
67
|
+
if (isFailure(status))
|
|
68
|
+
return status;
|
|
69
|
+
const repositoryScope = literalOrFail(artifactKind, sourcePath, "Repository scope", parsed.metadata["Repository scope"], VALID_REPOSITORY_SCOPES);
|
|
70
|
+
if (isFailure(repositoryScope))
|
|
71
|
+
return repositoryScope;
|
|
72
|
+
const freshness = literalOrFail(artifactKind, sourcePath, "Freshness", parsed.metadata["Freshness"], VALID_FRESHNESS_VALUES);
|
|
73
|
+
if (isFailure(freshness))
|
|
74
|
+
return freshness;
|
|
75
|
+
const adequacy = literalOrFail(artifactKind, sourcePath, "Adequacy", parsed.metadata["Adequacy"], VALID_ADEQUACY_VALUES);
|
|
76
|
+
if (isFailure(adequacy))
|
|
77
|
+
return adequacy;
|
|
78
|
+
const requiredEvidenceTruncated = literalOrFail(artifactKind, sourcePath, "Required evidence truncated", parsed.metadata["Required evidence truncated"], VALID_TRUNCATION_VALUES);
|
|
79
|
+
if (isFailure(requiredEvidenceTruncated))
|
|
80
|
+
return requiredEvidenceTruncated;
|
|
81
|
+
const indexIdentity = parsed.metadata["Index identity"];
|
|
82
|
+
if (!indexIdentity || indexIdentity.length === 0) {
|
|
83
|
+
return makeFailure(artifactKind, sourcePath, "MISSING_CANONICAL_IDENTITY", `Artifact "${artifactKind}" at "${sourcePath}" is missing a non-empty canonical "Index identity".`, "Index identity", "present");
|
|
84
|
+
}
|
|
85
|
+
const document = {
|
|
86
|
+
documentKind: expectedKind,
|
|
87
|
+
role: expectedRole,
|
|
88
|
+
schemaVersion,
|
|
89
|
+
schemaMajor: 1,
|
|
90
|
+
status,
|
|
91
|
+
repositoryScope,
|
|
92
|
+
freshness,
|
|
93
|
+
adequacy,
|
|
94
|
+
requiredEvidenceTruncated,
|
|
95
|
+
contextCapsuleSchemaVersion: parsed.metadata["Context capsule schema version"],
|
|
96
|
+
retrievalAuditSchemaVersion: parsed.metadata["Retrieval audit schema version"],
|
|
97
|
+
toolName: parsed.metadata["Tool name"],
|
|
98
|
+
toolVersion: parsed.metadata["Tool version"],
|
|
99
|
+
indexIdentity,
|
|
100
|
+
rawMetadata: parsed.metadata,
|
|
101
|
+
sections: parsed.sections,
|
|
102
|
+
sectionOrder: parsed.sectionOrder,
|
|
103
|
+
metadataOrder: parsed.metadataOrder,
|
|
104
|
+
warnings: []
|
|
105
|
+
};
|
|
106
|
+
if (isRetrievalReportKind(expectedKind)) {
|
|
107
|
+
document.requestSchemaVersion = parsed.metadata["Request schema version"];
|
|
108
|
+
const fullFileFallbackUsed = literalOrFail(artifactKind, sourcePath, "Full-file fallback used", parsed.metadata["Full-file fallback used"], VALID_TRUNCATION_VALUES);
|
|
109
|
+
if (isFailure(fullFileFallbackUsed))
|
|
110
|
+
return fullFileFallbackUsed;
|
|
111
|
+
document.fullFileFallbackUsed = fullFileFallbackUsed;
|
|
112
|
+
const determinismChecked = literalOrFail(artifactKind, sourcePath, "Determinism checked", parsed.metadata["Determinism checked"], VALID_TRUNCATION_VALUES);
|
|
113
|
+
if (isFailure(determinismChecked))
|
|
114
|
+
return determinismChecked;
|
|
115
|
+
document.determinismChecked = determinismChecked;
|
|
116
|
+
}
|
|
117
|
+
if (isTestKind(expectedKind)) {
|
|
118
|
+
const responsibilityMappingsTruncated = literalOrFail(artifactKind, sourcePath, "Responsibility mappings truncated", parsed.metadata["Responsibility mappings truncated"], VALID_TRUNCATION_VALUES);
|
|
119
|
+
if (isFailure(responsibilityMappingsTruncated))
|
|
120
|
+
return responsibilityMappingsTruncated;
|
|
121
|
+
document.responsibilityMappingsTruncated = responsibilityMappingsTruncated;
|
|
122
|
+
// Preserved verbatim, never validated against the orchestrator's internal
|
|
123
|
+
// CriticalResponsibilityMappingState enum -- see supplementalContextTypes.ts.
|
|
124
|
+
const criticalStatus = parsed.metadata["Critical responsibility mapping status"];
|
|
125
|
+
if (!criticalStatus || criticalStatus.length === 0) {
|
|
126
|
+
return makeFailure(artifactKind, sourcePath, "MISSING_REQUIRED_METADATA", `Artifact "${artifactKind}" at "${sourcePath}" is missing a non-empty "Critical responsibility mapping status".`, "Critical responsibility mapping status", "present");
|
|
127
|
+
}
|
|
128
|
+
document.criticalResponsibilityMappingStatus = criticalStatus;
|
|
129
|
+
}
|
|
130
|
+
if (parsed.duplicateMetadataKeys.length > 0) {
|
|
131
|
+
document.warnings.push(`Duplicate metadata keys were ignored (first occurrence kept): ${parsed.duplicateMetadataKeys.join(", ")}.`);
|
|
132
|
+
}
|
|
133
|
+
if (parsed.duplicateSectionHeadings.length > 0) {
|
|
134
|
+
document.warnings.push(`Duplicate section headings were ignored (first occurrence kept): ${parsed.duplicateSectionHeadings.join(", ")}.`);
|
|
135
|
+
}
|
|
136
|
+
if (parsed.emptyMetadataKeys.length > 0) {
|
|
137
|
+
document.warnings.push(`Metadata keys had empty values: ${parsed.emptyMetadataKeys.join(", ")}.`);
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
ok: true,
|
|
141
|
+
artifactKind,
|
|
142
|
+
sourcePath,
|
|
143
|
+
schemaVersion,
|
|
144
|
+
schemaMajor: 1,
|
|
145
|
+
artifact: document,
|
|
146
|
+
rawArtifact: { metadata: parsed.metadata, sections: parsed.sections }
|
|
147
|
+
};
|
|
148
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readMyDevKitContextCapsuleV1, readMyDevKitRetrievalAuditRecordV1, readOrchestratorWorkflowInstructionPacketV1 } from "../../../evaluation/upstreamArtifacts/index.js";
|
|
1
|
+
import { readImplementationContextPacketV1, readImplementationContextRetrievalReportV1, readMyDevKitContextCapsuleV1, readMyDevKitRetrievalAuditRecordV1, readOrchestratorWorkflowInstructionPacketV1, readTestContextPacketV1, readTestContextRetrievalReportV1, validateOrchestratorContextReadinessResultV1 } from "../../../evaluation/upstreamArtifacts/index.js";
|
|
2
2
|
import { checkMyDevKitContextArtifactConsistency } from "../../../evaluation/stageContextSelectors/index.js";
|
|
3
3
|
import { readStageContextExpectationFixtureV1 } from "../../../evaluation/stageContextExpectations/index.js";
|
|
4
4
|
import { readV043FullWorkflowLibraryFixture } from "./readV043FullWorkflowLibraryFixture.js";
|
|
@@ -265,20 +265,131 @@ export async function loadV043StrategyArtifacts(input) {
|
|
|
265
265
|
details: packetResult
|
|
266
266
|
});
|
|
267
267
|
}
|
|
268
|
+
// v0.4.4 Batch 3: producer-readiness bridge inputs -- every one is optional (section
|
|
269
|
+
// 11.2). Only a supplied-but-unreadable source becomes a load failure; an absent
|
|
270
|
+
// source is simply left off the payload for the bridge evaluator to treat as
|
|
271
|
+
// unavailable/not-applicable.
|
|
272
|
+
let implementationContextPacketSourcePath;
|
|
273
|
+
let implementationContextPacket;
|
|
274
|
+
if (input.implementationContextPacketPath !== undefined) {
|
|
275
|
+
const result = await readImplementationContextPacketV1(input.implementationContextPacketPath);
|
|
276
|
+
if (!result.ok) {
|
|
277
|
+
issues.push({
|
|
278
|
+
code: "IMPLEMENTATION_CONTEXT_PACKET_READ_FAILED",
|
|
279
|
+
fieldPath: "implementationContextPacket",
|
|
280
|
+
message: `Failed to read implementation-context packet: ${result.message}`,
|
|
281
|
+
sourcePath: result.sourcePath,
|
|
282
|
+
details: result
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
implementationContextPacketSourcePath = result.sourcePath;
|
|
287
|
+
implementationContextPacket = result.artifact;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
let implementationContextRetrievalReportSourcePath;
|
|
291
|
+
let implementationContextRetrievalReport;
|
|
292
|
+
if (input.implementationContextRetrievalReportPath !== undefined) {
|
|
293
|
+
const result = await readImplementationContextRetrievalReportV1(input.implementationContextRetrievalReportPath);
|
|
294
|
+
if (!result.ok) {
|
|
295
|
+
issues.push({
|
|
296
|
+
code: "IMPLEMENTATION_CONTEXT_RETRIEVAL_REPORT_READ_FAILED",
|
|
297
|
+
fieldPath: "implementationContextRetrievalReport",
|
|
298
|
+
message: `Failed to read implementation-context retrieval report: ${result.message}`,
|
|
299
|
+
sourcePath: result.sourcePath,
|
|
300
|
+
details: result
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
implementationContextRetrievalReportSourcePath = result.sourcePath;
|
|
305
|
+
implementationContextRetrievalReport = result.artifact;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
let testContextPacketSourcePath;
|
|
309
|
+
let testContextPacket;
|
|
310
|
+
if (input.testContextPacketPath !== undefined) {
|
|
311
|
+
const result = await readTestContextPacketV1(input.testContextPacketPath);
|
|
312
|
+
if (!result.ok) {
|
|
313
|
+
issues.push({
|
|
314
|
+
code: "TEST_CONTEXT_PACKET_READ_FAILED",
|
|
315
|
+
fieldPath: "testContextPacket",
|
|
316
|
+
message: `Failed to read test-context packet: ${result.message}`,
|
|
317
|
+
sourcePath: result.sourcePath,
|
|
318
|
+
details: result
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
testContextPacketSourcePath = result.sourcePath;
|
|
323
|
+
testContextPacket = result.artifact;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
let testContextRetrievalReportSourcePath;
|
|
327
|
+
let testContextRetrievalReport;
|
|
328
|
+
if (input.testContextRetrievalReportPath !== undefined) {
|
|
329
|
+
const result = await readTestContextRetrievalReportV1(input.testContextRetrievalReportPath);
|
|
330
|
+
if (!result.ok) {
|
|
331
|
+
issues.push({
|
|
332
|
+
code: "TEST_CONTEXT_RETRIEVAL_REPORT_READ_FAILED",
|
|
333
|
+
fieldPath: "testContextRetrievalReport",
|
|
334
|
+
message: `Failed to read test-context retrieval report: ${result.message}`,
|
|
335
|
+
sourcePath: result.sourcePath,
|
|
336
|
+
details: result
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
testContextRetrievalReportSourcePath = result.sourcePath;
|
|
341
|
+
testContextRetrievalReport = result.artifact;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
let readiness;
|
|
345
|
+
if (input.readiness !== undefined) {
|
|
346
|
+
const readinessResult = validateOrchestratorContextReadinessResultV1(input.readiness, "programmatic-input:readiness");
|
|
347
|
+
if (!readinessResult.ok) {
|
|
348
|
+
issues.push({
|
|
349
|
+
code: "READINESS_INPUT_INVALID",
|
|
350
|
+
fieldPath: "readiness",
|
|
351
|
+
message: `Readiness programmatic input is invalid: ${readinessResult.message}`,
|
|
352
|
+
details: readinessResult
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
readiness = readinessResult.artifact;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
268
359
|
if (issues.length > 0 || !expectationsResult.ok || !packetResult.ok || pairs.length !== input.contextArtifacts.length) {
|
|
269
360
|
return buildFailureResult(input, issues);
|
|
270
361
|
}
|
|
362
|
+
const payload = {
|
|
363
|
+
contextArtifacts: pairs,
|
|
364
|
+
workflowInstructionPacketSourcePath: packetResult.sourcePath,
|
|
365
|
+
workflowInstructionPacket: packetResult.artifact
|
|
366
|
+
};
|
|
367
|
+
if (implementationContextPacket !== undefined) {
|
|
368
|
+
payload.implementationContextPacketSourcePath = implementationContextPacketSourcePath;
|
|
369
|
+
payload.implementationContextPacket = implementationContextPacket;
|
|
370
|
+
}
|
|
371
|
+
if (implementationContextRetrievalReport !== undefined) {
|
|
372
|
+
payload.implementationContextRetrievalReportSourcePath = implementationContextRetrievalReportSourcePath;
|
|
373
|
+
payload.implementationContextRetrievalReport = implementationContextRetrievalReport;
|
|
374
|
+
}
|
|
375
|
+
if (testContextPacket !== undefined) {
|
|
376
|
+
payload.testContextPacketSourcePath = testContextPacketSourcePath;
|
|
377
|
+
payload.testContextPacket = testContextPacket;
|
|
378
|
+
}
|
|
379
|
+
if (testContextRetrievalReport !== undefined) {
|
|
380
|
+
payload.testContextRetrievalReportSourcePath = testContextRetrievalReportSourcePath;
|
|
381
|
+
payload.testContextRetrievalReport = testContextRetrievalReport;
|
|
382
|
+
}
|
|
383
|
+
if (readiness !== undefined) {
|
|
384
|
+
payload.readiness = readiness;
|
|
385
|
+
}
|
|
271
386
|
return {
|
|
272
387
|
status: "completed",
|
|
273
388
|
strategyId: input.strategyId,
|
|
274
389
|
input,
|
|
275
390
|
expectationsSourcePath: expectationsResult.sourcePath,
|
|
276
391
|
expectations: expectationsResult.fixture,
|
|
277
|
-
payload
|
|
278
|
-
contextArtifacts: pairs,
|
|
279
|
-
workflowInstructionPacketSourcePath: packetResult.sourcePath,
|
|
280
|
-
workflowInstructionPacket: packetResult.artifact
|
|
281
|
-
},
|
|
392
|
+
payload,
|
|
282
393
|
warnings: []
|
|
283
394
|
};
|
|
284
395
|
}
|