@dailephd/my-dev-kit-lab 0.4.4 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +468 -0
- package/README.md +3 -1
- package/dist/scripts/report-context-integrity-smoke.js +70 -0
- package/dist/src/evaluation/ecosystemFixtures/index.js +3 -0
- package/dist/src/evaluation/ecosystemFixtures/loadContextIntegrityFixture.js +102 -0
- package/dist/src/evaluation/ecosystemFixtures/manifestTypes.js +1 -0
- package/dist/src/evaluation/ecosystemFixtures/validateManifest.js +82 -0
- package/dist/src/evaluation/ecosystemFixtures/verifyFixtureHashes.js +45 -0
- package/dist/src/evaluation/stageContextMetrics/calculateAllocationMetrics.js +169 -0
- package/dist/src/evaluation/stageContextMetrics/calculateConditionCoverageMetrics.js +74 -0
- package/dist/src/evaluation/stageContextMetrics/calculateProducerConditionAgreement.js +113 -0
- package/dist/src/evaluation/stageContextMetrics/calculateReadinessAgreement.js +60 -0
- package/dist/src/evaluation/stageContextMetrics/calculateRunIntegrityAgreement.js +309 -0
- package/dist/src/evaluation/stageContextMetrics/calculateSupplementalRawAgreement.js +12 -2
- package/dist/src/evaluation/stageContextMetrics/calculateTruncationClassification.js +100 -0
- package/dist/src/evaluation/stageContextMetrics/evaluateProducerReadinessBridge.js +76 -5
- package/dist/src/evaluation/stageContextMetrics/index.js +4 -0
- package/dist/src/evaluation/stageContextMetrics/runIntegrityAgreementTypes.js +1 -0
- package/dist/src/evaluation/stageContextSelectors/contextArtifactConsistency.js +7 -0
- package/dist/src/evaluation/stageContextSelectors/index.js +1 -0
- package/dist/src/evaluation/stageContextSelectors/orchestratorRunIntegritySelectors.js +64 -0
- package/dist/src/evaluation/upstreamArtifacts/index.js +2 -0
- package/dist/src/evaluation/upstreamArtifacts/orchestratorRunIntegrityV1.js +33 -0
- package/dist/src/evaluation/upstreamArtifacts/readOrchestratorRunIntegrityV1.js +9 -0
- package/dist/src/evaluation/upstreamArtifacts/validateMyDevKitContextCapsuleV1.js +59 -2
- package/dist/src/evaluation/upstreamArtifacts/validateMyDevKitRetrievalAuditRecordV1.js +6 -1
- package/dist/src/evaluation/upstreamArtifacts/validateOrchestratorRunIntegrityV1.js +177 -0
- package/dist/src/report/experiments/buildContextIntegrityReport.js +204 -0
- package/dist/src/report/experiments/contextIntegrityReportModel.js +1 -0
- package/dist/src/report/experiments/index.js +5 -0
- package/dist/src/report/experiments/renderContextIntegrityHtml.js +98 -0
- package/dist/src/report/experiments/renderContextIntegrityJsonReport.js +3 -0
- package/dist/src/report/experiments/renderContextIntegrityText.js +111 -0
- package/dist/src/securityValidation/packageChecks/requiredPackageContents.js +33 -0
- package/dist/src/securityValidation/packageChecks/runPackageChecks.js +11 -5
- package/docs/METRICS.md +83 -0
- package/package.json +4 -2
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/corrected-replay/derived/run-integrity-evidence.json +99 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/corrected-replay/producer/implementation-audit.json +1585 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/corrected-replay/producer/implementation-capsule.json +11455 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/00-request.txt +1 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/architecture-context-packet.txt +82 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/behavior-model.txt +104 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/final-report.txt +41 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/implementation-context-packet.txt +114 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/implementation-report.txt +92 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/judge-report.txt +34 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/pseudocode-packet.txt +244 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/request-brief.txt +40 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/test-context-packet.txt +93 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/test-implementation-report.txt +69 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/test-strategy-packet.txt +354 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/artifacts/verification-report.txt +85 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/derived/run-integrity-evidence.json +98 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/architecture-audit.json +1169 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/architecture-request.json +29 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/implementation-audit.json +1494 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/implementation-capsule.json +11364 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/implementation-request.json +33 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/producer/test-request.json +74 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/reports/architecture-context-retrieval-report.txt +58 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/reports/implementation-context-retrieval-report.txt +75 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/reports/test-context-retrieval-report.txt +84 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/run.json +62 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/tool-versions/my-dev-kit-version.txt +1 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/failed-run/tool-versions/orchestrator-version.txt +1 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/manifests/corrected-replay-manifest.json +19 -0
- package/tests/fixtures/ecosystem/context-integrity/v0.4.5/manifests/failed-run-manifest.json +56 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.4/PROVENANCE.txt +18 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.4/context-capsule/complete-v1.0.0.json +556 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.4/retrieval-audit-record/complete-v1.0.0.json +238 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.3/run-integrity/PROVENANCE.txt +31 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.3/run-integrity/ready-pass-final-pass.json +132 -0
- package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.3/run-integrity/refresh-required-need-context.json +146 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export function selectReadinessClassification(evidence) {
|
|
2
|
+
return evidence.gate.readinessClassification;
|
|
3
|
+
}
|
|
4
|
+
export function selectContextReady(evidence) {
|
|
5
|
+
return evidence.gate.contextReady;
|
|
6
|
+
}
|
|
7
|
+
export function selectBlockingCodes(evidence) {
|
|
8
|
+
return evidence.gate.blockingCodes;
|
|
9
|
+
}
|
|
10
|
+
export function selectRecommendedCorrectionStage(evidence) {
|
|
11
|
+
return evidence.gate.recommendedCorrectionStage;
|
|
12
|
+
}
|
|
13
|
+
export function selectExpectedJudgeVerdict(evidence) {
|
|
14
|
+
return evidence.gate.expectedJudgeVerdict;
|
|
15
|
+
}
|
|
16
|
+
// Prompt mode is not a field the exact v1.2.3 gate contract exposes as a literal string --
|
|
17
|
+
// it is a derived per-stage decision (evaluateStageRunIntegrity()). The lab represents it
|
|
18
|
+
// via the same contextReady/blockedStageNames facts the gate already exposes rather than
|
|
19
|
+
// inventing a separate "promptMode" string the upstream contract does not itself declare.
|
|
20
|
+
export function selectStageMayRenderNormalPrompt(evidence, stageName) {
|
|
21
|
+
const contextSensitive = evidence.gate.blockedStageNames.length > 0 || stageName === "implementation" || stageName === "test-implementation";
|
|
22
|
+
if (!contextSensitive)
|
|
23
|
+
return undefined;
|
|
24
|
+
return !evidence.gate.blockedStageNames.includes(stageName);
|
|
25
|
+
}
|
|
26
|
+
export function selectJudgeArtifactPresent(evidence) {
|
|
27
|
+
return evidence.judgeIntegrity?.judgeArtifactPresent;
|
|
28
|
+
}
|
|
29
|
+
export function selectJudgeVerdictParseStatus(evidence) {
|
|
30
|
+
return evidence.judgeIntegrity?.judgeVerdictParseStatus;
|
|
31
|
+
}
|
|
32
|
+
export function selectAuthoredJudgeVerdict(evidence) {
|
|
33
|
+
return evidence.judgeIntegrity?.authoredJudgeVerdict;
|
|
34
|
+
}
|
|
35
|
+
export function selectJudgeVerdictMatchesExpected(evidence) {
|
|
36
|
+
return evidence.judgeIntegrity?.judgeVerdictMatchesExpected;
|
|
37
|
+
}
|
|
38
|
+
export function selectJudgeVerdictAccepted(evidence) {
|
|
39
|
+
return evidence.judgeIntegrity?.judgeVerdictAccepted;
|
|
40
|
+
}
|
|
41
|
+
export function selectAcceptedCorrectionStage(evidence) {
|
|
42
|
+
return evidence.judgeIntegrity?.acceptedCorrectionStage;
|
|
43
|
+
}
|
|
44
|
+
export function selectAcceptedCorrectionRoute(evidence) {
|
|
45
|
+
return evidence.judgeIntegrity?.acceptedCorrectionRoute;
|
|
46
|
+
}
|
|
47
|
+
export function selectJudgeFinalReportEligible(evidence) {
|
|
48
|
+
return evidence.judgeIntegrity?.finalReportEligible;
|
|
49
|
+
}
|
|
50
|
+
export function selectFinalReportEligible(evidence) {
|
|
51
|
+
return evidence.finalReportEligibility?.eligible;
|
|
52
|
+
}
|
|
53
|
+
export function selectFinalArtifactPresent(evidence) {
|
|
54
|
+
return evidence.finalArtifactPresent;
|
|
55
|
+
}
|
|
56
|
+
export function selectFinalArtifactVerdict(evidence) {
|
|
57
|
+
return evidence.finalArtifactVerdict;
|
|
58
|
+
}
|
|
59
|
+
export function selectLifecycleEntries(evidence) {
|
|
60
|
+
return evidence.lifecycle;
|
|
61
|
+
}
|
|
62
|
+
export function selectLifecycleEntryForStage(evidence, stageName) {
|
|
63
|
+
return evidence.lifecycle.find((entry) => entry.stageName === stageName);
|
|
64
|
+
}
|
|
@@ -7,3 +7,5 @@ export { readImplementationContextRetrievalReportV1 } from "./readImplementation
|
|
|
7
7
|
export { readTestContextPacketV1 } from "./readTestContextPacketV1.js";
|
|
8
8
|
export { readTestContextRetrievalReportV1 } from "./readTestContextRetrievalReportV1.js";
|
|
9
9
|
export { READINESS_DECISIONS, READINESS_CLASSIFICATIONS, validateOrchestratorContextReadinessResultV1, checkSupplementalReadinessIdentityConsistency } from "./orchestratorContextReadinessResultV1.js";
|
|
10
|
+
export { readOrchestratorRunIntegrityEvidenceV1 } from "./readOrchestratorRunIntegrityV1.js";
|
|
11
|
+
export { validateOrchestratorRunIntegrityEvidenceV1 } from "./validateOrchestratorRunIntegrityV1.js";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// --- src/judgeParser.ts ---------------------------------------------------------------
|
|
2
|
+
export const JUDGE_VERDICTS = [
|
|
3
|
+
"PASS",
|
|
4
|
+
"DESIGN_INCOMPLETE",
|
|
5
|
+
"PSEUDOCODE_INCOMPLETE",
|
|
6
|
+
"IMPLEMENTATION_MISMATCH",
|
|
7
|
+
"TEST_COVERAGE_INCOMPLETE",
|
|
8
|
+
"ARCHITECTURE_MISMATCH",
|
|
9
|
+
"NEED_VERIFICATION",
|
|
10
|
+
"NEED_CONTEXT",
|
|
11
|
+
"SCOPE_VIOLATION",
|
|
12
|
+
"BLOCKED"
|
|
13
|
+
];
|
|
14
|
+
// --- src/correctionRouter.ts ----------------------------------------------------------
|
|
15
|
+
export const CORRECTABLE_STAGES = [
|
|
16
|
+
"architecture-context",
|
|
17
|
+
"behavior-model",
|
|
18
|
+
"pseudocode-packet",
|
|
19
|
+
"test-strategy",
|
|
20
|
+
"test-implementation",
|
|
21
|
+
"implementation",
|
|
22
|
+
"verification",
|
|
23
|
+
"target-architecture"
|
|
24
|
+
];
|
|
25
|
+
export const ROUTE_STATUSES = ["pass", "correction_required", "blocked", "unknown_verdict", "missing_verdict"];
|
|
26
|
+
// --- src/runIntegrityGate.ts ----------------------------------------------------------
|
|
27
|
+
export const RUN_INTEGRITY_READINESS_CLASSIFICATIONS = ["not-required", "ready", "refresh-required"];
|
|
28
|
+
export const CONTEXT_SENSITIVE_STAGE_NAMES = ["implementation", "test-implementation"];
|
|
29
|
+
// --- src/judgeIntegrity.ts --------------------------------------------------------------
|
|
30
|
+
export const JUDGE_VERDICT_PARSE_STATUSES = ["parsed", "missing-artifact", "missing-verdict", "unknown-verdict"];
|
|
31
|
+
// --- src/artifactLifecycle.ts -----------------------------------------------------------
|
|
32
|
+
export const ARTIFACT_LIFECYCLE_STATES = ["missing", "incomplete", "blocked", "complete", "stale"];
|
|
33
|
+
export const MANUAL_ARTIFACT_LIFECYCLE_STATES = ["incomplete", "blocked", "complete"];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { readJsonArtifactFile } from "./readJsonArtifact.js";
|
|
2
|
+
import { validateOrchestratorRunIntegrityEvidenceV1 } from "./validateOrchestratorRunIntegrityV1.js";
|
|
3
|
+
const ARTIFACT_KIND = "orchestrator-run-integrity-evidence-v1";
|
|
4
|
+
export async function readOrchestratorRunIntegrityEvidenceV1(sourcePath) {
|
|
5
|
+
const loaded = await readJsonArtifactFile(ARTIFACT_KIND, sourcePath);
|
|
6
|
+
if (!loaded.ok)
|
|
7
|
+
return loaded;
|
|
8
|
+
return validateOrchestratorRunIntegrityEvidenceV1(loaded.value, loaded.sourcePath);
|
|
9
|
+
}
|
|
@@ -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
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, validateRoleContextSummary, validateTruncationSummary } from "./validateMyDevKitContextCapsuleV1.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) {
|
|
@@ -83,6 +83,11 @@ export function validateMyDevKitRetrievalAuditRecordV1(value, sourcePath) {
|
|
|
83
83
|
contextAdequacy: validateContextAdequacyStatement(ctx, requiredField(ctx, value, "contextAdequacy", "contextAdequacy"), "contextAdequacy"),
|
|
84
84
|
roleContext: validateRoleContextSummary(ctx, requiredField(ctx, value, "roleContext", "roleContext"), "roleContext"),
|
|
85
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
|
+
: {}),
|
|
86
91
|
roleAdequacy: validateRoleAdequacyStatement(ctx, requiredField(ctx, value, "roleAdequacy", "roleAdequacy"), "roleAdequacy"),
|
|
87
92
|
freshness: validateFreshnessSummary(ctx, requiredField(ctx, value, "freshness", "freshness"), "freshness"),
|
|
88
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,204 @@
|
|
|
1
|
+
// v0.4.5 Batch 5: builds the bounded ContextIntegrityReportV1 from already-calculated
|
|
2
|
+
// Batch 1-4 results. Never recalculates allocation, condition coverage, agreement states,
|
|
3
|
+
// hashes, determinism, or immutability -- it only bounds and reshapes values the caller
|
|
4
|
+
// already computed via evaluateProducerReadinessBridge, verifyFixtureHashes, and
|
|
5
|
+
// calculateStageContextDeterminism.
|
|
6
|
+
import { V043_REPORT_DETAIL_LIMIT } from "./contextStrategyComparisonV043ReportModel.js";
|
|
7
|
+
const CORRECTED_REPLAY_LIMITATION = "This corrected-replay fixture is a hand-distilled representation of the exact validated local my-dev-kit v1.10.4 and my-dev-kit-orchestrator v1.2.3 contracts, applied to the same request, target, and active-index identity as the paired failed-run fixture. It is not a live capture of a complete ten-stage AI-authored implementation workflow, and it is not proof that every future run against these contracts will behave identically.";
|
|
8
|
+
function boundItems(source, limit = V043_REPORT_DETAIL_LIMIT) {
|
|
9
|
+
const items = source.slice(0, limit);
|
|
10
|
+
return { totalCount: source.length, displayedCount: items.length, omittedCount: source.length - items.length, items };
|
|
11
|
+
}
|
|
12
|
+
function toContradiction(c) {
|
|
13
|
+
return { code: c.code, fieldPath: c.fieldPath, expected: c.expected, observed: c.observed, reason: c.reason };
|
|
14
|
+
}
|
|
15
|
+
function agreementFromRunIntegrity(component) {
|
|
16
|
+
return {
|
|
17
|
+
availability: component.availability,
|
|
18
|
+
outcome: component.outcome,
|
|
19
|
+
contradictions: boundItems(component.contradictions.map(toContradiction)),
|
|
20
|
+
reason: component.reason
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function unavailableAgreement(reason) {
|
|
24
|
+
return { availability: "unavailable", outcome: "insufficient-evidence", contradictions: boundItems([]), reason };
|
|
25
|
+
}
|
|
26
|
+
export function buildContextIntegrityReport(input) {
|
|
27
|
+
const { manifest, hashVerification, capsule, bridgeResult } = input;
|
|
28
|
+
const side = bridgeResult.implementation ?? bridgeResult.testImplementation;
|
|
29
|
+
const runIntegrity = bridgeResult.runIntegrityEvaluation;
|
|
30
|
+
const derivedCount = manifest.artifacts.filter((a) => a.derived).length;
|
|
31
|
+
const byteExactCount = manifest.artifacts.filter((a) => a.byteExact).length;
|
|
32
|
+
const allocationAgg = side?.groupAllocationEvaluation.aggregate ?? null;
|
|
33
|
+
const spillover = side?.groupAllocationEvaluation.spillover ?? null;
|
|
34
|
+
const conditionCoverage = side?.conditionCoverageEvaluation ?? null;
|
|
35
|
+
const conditionAwareTruncation = side?.conditionAwareTruncationEvaluation ?? null;
|
|
36
|
+
const unavailableSections = [];
|
|
37
|
+
const notes = [];
|
|
38
|
+
if (!side)
|
|
39
|
+
unavailableSections.push("producer");
|
|
40
|
+
if (!runIntegrity)
|
|
41
|
+
unavailableSections.push("run-integrity");
|
|
42
|
+
if (conditionCoverage?.availability !== "available")
|
|
43
|
+
unavailableSections.push("condition-coverage");
|
|
44
|
+
return {
|
|
45
|
+
schemaVersion: "1.0.0",
|
|
46
|
+
detailLimit: V043_REPORT_DETAIL_LIMIT,
|
|
47
|
+
fixture: {
|
|
48
|
+
fixtureId: manifest.fixtureId,
|
|
49
|
+
kind: input.fixtureKind,
|
|
50
|
+
description: manifest.description,
|
|
51
|
+
myDevKitCommit: manifest.myDevKit.commit,
|
|
52
|
+
orchestratorCommit: manifest.orchestrator.commit,
|
|
53
|
+
targetRepositoryIdentity: manifest.targetRepositoryIdentity,
|
|
54
|
+
activeIndexIdentity: manifest.activeIndexIdentity,
|
|
55
|
+
manifestSchemaVersion: manifest.manifestSchemaVersion,
|
|
56
|
+
trackedArtifactCount: manifest.artifacts.length,
|
|
57
|
+
derivedArtifactCount: derivedCount,
|
|
58
|
+
byteExactArtifactCount: byteExactCount,
|
|
59
|
+
artifacts: boundItems(manifest.artifacts.map((a) => ({
|
|
60
|
+
fixtureRelativePath: a.fixtureRelativePath,
|
|
61
|
+
role: a.role,
|
|
62
|
+
derived: a.derived,
|
|
63
|
+
byteExact: a.byteExact,
|
|
64
|
+
provenanceOnly: a.provenanceOnly
|
|
65
|
+
}))),
|
|
66
|
+
hashVerification: {
|
|
67
|
+
ok: hashVerification.ok,
|
|
68
|
+
checkedCount: hashVerification.checkedCount,
|
|
69
|
+
issues: boundItems(hashVerification.issues.map((i) => ({ code: i.code, fixtureRelativePath: i.fixtureRelativePath, message: i.message })))
|
|
70
|
+
},
|
|
71
|
+
correctedReplayLimitation: input.fixtureKind === "corrected-replay" ? CORRECTED_REPLAY_LIMITATION : ""
|
|
72
|
+
},
|
|
73
|
+
producerIdentity: {
|
|
74
|
+
toolName: capsule?.tool.name ?? null,
|
|
75
|
+
toolVersion: capsule?.tool.version ?? null,
|
|
76
|
+
role: capsule?.request.role ?? null,
|
|
77
|
+
projectRoot: capsule?.index.projectRoot ?? null,
|
|
78
|
+
indexPath: capsule?.index.indexPath ?? null,
|
|
79
|
+
roleAdequacyStatus: capsule?.roleAdequacy.status ?? null
|
|
80
|
+
},
|
|
81
|
+
allocation: {
|
|
82
|
+
availability: allocationAgg?.availability ?? "unavailable",
|
|
83
|
+
groupCount: allocationAgg?.groupCount ?? 0,
|
|
84
|
+
totalRequiredOmitted: allocationAgg?.totalRequiredOmitted ?? null,
|
|
85
|
+
totalOptionalOmitted: allocationAgg?.totalOptionalOmitted ?? null,
|
|
86
|
+
aggregateCapacityUsed: null,
|
|
87
|
+
aggregateCapacityRemaining: null,
|
|
88
|
+
groupsWithRequiredOmission: allocationAgg?.groupsWithRequiredOmission ?? [],
|
|
89
|
+
groupsWithOptionalOnlyOmission: allocationAgg?.groupsWithOptionalOnlyOmission ?? [],
|
|
90
|
+
perGroup: boundItems((side?.groupAllocationEvaluation.perGroup ?? []).map((g) => ({
|
|
91
|
+
groupId: g.groupId,
|
|
92
|
+
availability: g.availability,
|
|
93
|
+
required: g.required,
|
|
94
|
+
reservation: g.reservation,
|
|
95
|
+
initiallySelectedCount: g.initiallySelectedCount,
|
|
96
|
+
unusedReservationContributed: g.unusedReservationContributed,
|
|
97
|
+
borrowedCapacity: g.borrowedCapacity,
|
|
98
|
+
requiredOmittedCount: g.requiredOmittedCount,
|
|
99
|
+
optionalOmittedCount: g.optionalOmittedCount,
|
|
100
|
+
adequacyAffected: g.adequacyAffected
|
|
101
|
+
})))
|
|
102
|
+
},
|
|
103
|
+
spillover: {
|
|
104
|
+
availability: spillover?.availability ?? "unavailable",
|
|
105
|
+
groupsContributing: spillover?.groupsContributing ?? [],
|
|
106
|
+
groupsBorrowing: spillover?.groupsBorrowing ?? [],
|
|
107
|
+
totalContributed: spillover?.totalContributed ?? null,
|
|
108
|
+
totalBorrowed: spillover?.totalBorrowed ?? null,
|
|
109
|
+
contributionCoversBorrowing: spillover?.contributionCoversBorrowing ?? null,
|
|
110
|
+
reason: spillover?.reason ?? null
|
|
111
|
+
},
|
|
112
|
+
truncation: {
|
|
113
|
+
availability: conditionAwareTruncation?.availability ?? "unavailable",
|
|
114
|
+
state: conditionAwareTruncation?.state ?? "unsupported-legacy-diagnostics",
|
|
115
|
+
requiredEvidenceLost: conditionAwareTruncation?.requiredEvidenceLost ?? null,
|
|
116
|
+
requiredOmittedTotal: conditionAwareTruncation?.requiredOmittedTotal ?? null,
|
|
117
|
+
optionalOmittedTotal: conditionAwareTruncation?.optionalOmittedTotal ?? null,
|
|
118
|
+
lostRequiredConditionIds: conditionAwareTruncation?.lostRequiredConditionIds ?? [],
|
|
119
|
+
contradictions: boundItems((conditionAwareTruncation?.contradictionCodes ?? []).map((code) => ({ code, fieldPath: "truncation", expected: null, observed: null, reason: conditionAwareTruncation?.reason ?? "" })))
|
|
120
|
+
},
|
|
121
|
+
conditionCoverage: {
|
|
122
|
+
availability: conditionCoverage?.availability ?? "unavailable",
|
|
123
|
+
requiredConditionsTotal: conditionCoverage?.requiredConditionsTotal.count ?? null,
|
|
124
|
+
requiredConditionsSatisfied: conditionCoverage?.requiredConditionsSatisfied.count ?? null,
|
|
125
|
+
requiredConditionsMissing: conditionCoverage?.requiredConditionsMissing.evidenceKeys ?? [],
|
|
126
|
+
requiredConditionsLost: conditionCoverage?.requiredConditionsLost.evidenceKeys ?? [],
|
|
127
|
+
lastWitnessLossCount: conditionCoverage?.lastWitnessLoss.count ?? null,
|
|
128
|
+
witnessEvidence: boundItems((conditionCoverage?.witnessEvidence ?? []).map((w) => ({
|
|
129
|
+
conditionId: w.conditionId,
|
|
130
|
+
required: w.required,
|
|
131
|
+
coverageState: w.coverageState,
|
|
132
|
+
retainedWitnessCount: w.retainedWitnessCount,
|
|
133
|
+
retainedWitnessIds: boundItems(w.retainedWitnessIds),
|
|
134
|
+
adequateWitnessRemains: w.adequateWitnessRemains,
|
|
135
|
+
lossReason: w.lossReason,
|
|
136
|
+
evidenceGroupIds: w.evidenceGroupIds
|
|
137
|
+
}))),
|
|
138
|
+
reason: conditionCoverage?.reason ?? null
|
|
139
|
+
},
|
|
140
|
+
producerConditionAgreement: side
|
|
141
|
+
? {
|
|
142
|
+
availability: side.producerConditionAgreement.availability,
|
|
143
|
+
outcome: side.producerConditionAgreement.outcome,
|
|
144
|
+
contradictions: boundItems(side.producerConditionAgreement.contradictionCodes.map((code) => ({ code, fieldPath: "roleAdequacy", expected: null, observed: null, reason: side.producerConditionAgreement.reason ?? "" }))),
|
|
145
|
+
reason: side.producerConditionAgreement.reason
|
|
146
|
+
}
|
|
147
|
+
: unavailableAgreement("No producer side was supplied."),
|
|
148
|
+
requiredEvidenceLossAgreement: side
|
|
149
|
+
? {
|
|
150
|
+
availability: side.requiredEvidenceLossAgreement.availability,
|
|
151
|
+
outcome: side.requiredEvidenceLossAgreement.outcome,
|
|
152
|
+
contradictions: boundItems(side.requiredEvidenceLossAgreement.contradictionCodes.map((code) => ({ code, fieldPath: "truncation.requiredEvidenceLost", expected: null, observed: null, reason: side.requiredEvidenceLossAgreement.reason ?? "" }))),
|
|
153
|
+
reason: side.requiredEvidenceLossAgreement.reason
|
|
154
|
+
}
|
|
155
|
+
: unavailableAgreement("No producer side was supplied."),
|
|
156
|
+
capsuleAuditAgreement: side
|
|
157
|
+
? {
|
|
158
|
+
availability: side.capsuleAuditConditionAgreement.availability,
|
|
159
|
+
consistent: side.capsuleAuditConditionAgreement.consistent,
|
|
160
|
+
contradictingFieldPaths: side.capsuleAuditConditionAgreement.contradictingFieldPaths
|
|
161
|
+
}
|
|
162
|
+
: { availability: "unavailable", consistent: null, contradictingFieldPaths: [] },
|
|
163
|
+
supplementalRawAgreement: side?.packetAgreement || side?.reportAgreement
|
|
164
|
+
? {
|
|
165
|
+
availability: "available",
|
|
166
|
+
contradictingFields: [...(side.packetAgreement?.contradictions ?? []), ...(side.reportAgreement?.contradictions ?? [])].map((f) => f.field),
|
|
167
|
+
upstreamProducerParityPreserved: side.packetAgreement?.upstreamProducerParityPreserved ?? side.reportAgreement?.upstreamProducerParityPreserved ?? null
|
|
168
|
+
}
|
|
169
|
+
: null,
|
|
170
|
+
producerReadinessAgreement: bridgeResult.producerReadinessRelationship
|
|
171
|
+
? {
|
|
172
|
+
availability: bridgeResult.producerReadinessRelationship.availability,
|
|
173
|
+
outcome: bridgeResult.producerReadinessRelationship.outcome,
|
|
174
|
+
contradictions: boundItems(bridgeResult.producerReadinessRelationship.contradictionCodes.map((code) => ({ code, fieldPath: "readiness", expected: null, observed: null, reason: bridgeResult.producerReadinessRelationship.reason ?? "" }))),
|
|
175
|
+
reason: bridgeResult.producerReadinessRelationship.reason
|
|
176
|
+
}
|
|
177
|
+
: unavailableAgreement("No producer/readiness relationship was calculated."),
|
|
178
|
+
readinessPromptAgreement: runIntegrity ? agreementFromRunIntegrity(runIntegrity.readinessPrompt) : unavailableAgreement("No run-integrity evidence was supplied."),
|
|
179
|
+
readinessExpectedJudgeAgreement: runIntegrity ? agreementFromRunIntegrity(runIntegrity.readinessExpectedJudge) : unavailableAgreement("No run-integrity evidence was supplied."),
|
|
180
|
+
expectedActualJudgeAgreement: runIntegrity ? agreementFromRunIntegrity(runIntegrity.expectedActualJudge) : unavailableAgreement("No run-integrity evidence was supplied."),
|
|
181
|
+
judgeCorrectionAgreement: runIntegrity ? agreementFromRunIntegrity(runIntegrity.judgeCorrection) : unavailableAgreement("No run-integrity evidence was supplied."),
|
|
182
|
+
judgeFinalEligibilityAgreement: runIntegrity ? agreementFromRunIntegrity(runIntegrity.judgeFinalEligibility) : unavailableAgreement("No run-integrity evidence was supplied."),
|
|
183
|
+
eligibilityFinalArtifactAgreement: runIntegrity ? agreementFromRunIntegrity(runIntegrity.eligibilityFinalArtifact) : unavailableAgreement("No run-integrity evidence was supplied."),
|
|
184
|
+
lifecycleIntegrityAgreement: runIntegrity ? agreementFromRunIntegrity(runIntegrity.lifecycleIntegrity) : unavailableAgreement("No run-integrity evidence was supplied."),
|
|
185
|
+
endToEnd: runIntegrity
|
|
186
|
+
? { category: runIntegrity.endToEndSummary.category, componentOutcomes: runIntegrity.endToEndSummary.componentOutcomes, contradictingComponents: runIntegrity.endToEndSummary.contradictingComponents }
|
|
187
|
+
: null,
|
|
188
|
+
determinism: input.determinism
|
|
189
|
+
? {
|
|
190
|
+
availability: input.determinism.availability,
|
|
191
|
+
repeatCount: input.determinism.repeatCount,
|
|
192
|
+
deterministic: input.determinism.deterministic,
|
|
193
|
+
baselineSha256: input.determinism.baselineSha256,
|
|
194
|
+
mismatchRunNumbers: input.determinism.mismatchRunNumbers,
|
|
195
|
+
reason: input.determinism.reason
|
|
196
|
+
}
|
|
197
|
+
: { availability: "not-applicable", repeatCount: 1, deterministic: null, baselineSha256: null, mismatchRunNumbers: [], reason: "Determinism was not evaluated for this report." },
|
|
198
|
+
immutability: {
|
|
199
|
+
fixtureSelfImmutable: input.fixtureSelfImmutable ?? null,
|
|
200
|
+
fixtureImmutabilityReason: input.fixtureSelfImmutableReason ?? (input.fixtureSelfImmutable === undefined ? "Fixture self-immutability was not checked for this report." : null)
|
|
201
|
+
},
|
|
202
|
+
limitations: { unavailableSections, notes }
|
|
203
|
+
};
|
|
204
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|