@dailephd/my-dev-kit-lab 0.4.2 → 0.4.4

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.
Files changed (113) hide show
  1. package/README.md +28 -113
  2. package/benchmarks/contracts/todo-behavior.md +1 -1
  3. package/benchmarks/projects/task-analytics-large-mixed/README.md +2 -0
  4. package/benchmarks/projects/task-workflow-medium-ts/README.md +3 -1
  5. package/dist/src/evaluation/stageContextDeterminism/calculateStageContextDeterminism.js +52 -0
  6. package/dist/src/evaluation/stageContextDeterminism/canonicalizeStageContextRun.js +53 -0
  7. package/dist/src/evaluation/stageContextDeterminism/index.js +2 -0
  8. package/dist/src/evaluation/stageContextDeterminism/types.js +1 -0
  9. package/dist/src/evaluation/stageContextExpectations/index.js +2 -0
  10. package/dist/src/evaluation/stageContextExpectations/producerReadinessExpectationTypes.js +8 -0
  11. package/dist/src/evaluation/stageContextExpectations/readStageContextExpectationFixtureV1.js +50 -0
  12. package/dist/src/evaluation/stageContextExpectations/readTypes.js +1 -0
  13. package/dist/src/evaluation/stageContextExpectations/types.js +1 -0
  14. package/dist/src/evaluation/stageContextExpectations/validation.js +768 -0
  15. package/dist/src/evaluation/stageContextMetrics/calculateAllocationMetrics.js +96 -0
  16. package/dist/src/evaluation/stageContextMetrics/calculateArtifactStateMetrics.js +130 -0
  17. package/dist/src/evaluation/stageContextMetrics/calculateContextSizeMetrics.js +85 -0
  18. package/dist/src/evaluation/stageContextMetrics/calculateCriticalityMetrics.js +112 -0
  19. package/dist/src/evaluation/stageContextMetrics/calculateExpectationMetrics.js +103 -0
  20. package/dist/src/evaluation/stageContextMetrics/calculateOwnerMetrics.js +84 -0
  21. package/dist/src/evaluation/stageContextMetrics/calculateReadinessAgreement.js +152 -0
  22. package/dist/src/evaluation/stageContextMetrics/calculateResponsibilityMappingMetrics.js +36 -0
  23. package/dist/src/evaluation/stageContextMetrics/calculateSupplementalRawAgreement.js +50 -0
  24. package/dist/src/evaluation/stageContextMetrics/calculateTruncationClassification.js +44 -0
  25. package/dist/src/evaluation/stageContextMetrics/collectContextCapsuleEvidence.js +312 -0
  26. package/dist/src/evaluation/stageContextMetrics/collectRetrievalAuditEvidence.js +35 -0
  27. package/dist/src/evaluation/stageContextMetrics/collectWorkflowInstructionEvidence.js +137 -0
  28. package/dist/src/evaluation/stageContextMetrics/evaluateProducerReadinessBridge.js +127 -0
  29. package/dist/src/evaluation/stageContextMetrics/evaluateV043StageContextExecution.js +247 -0
  30. package/dist/src/evaluation/stageContextMetrics/index.js +17 -0
  31. package/dist/src/evaluation/stageContextMetrics/matchStageContextExpectations.js +38 -0
  32. package/dist/src/evaluation/stageContextMetrics/producerReadinessMetricTypes.js +1 -0
  33. package/dist/src/evaluation/stageContextMetrics/targetKeys.js +35 -0
  34. package/dist/src/evaluation/stageContextMetrics/types.js +1 -0
  35. package/dist/src/evaluation/stageContextSelectors/contextArtifactConsistency.js +89 -0
  36. package/dist/src/evaluation/stageContextSelectors/contextCapsuleSelectors.js +126 -0
  37. package/dist/src/evaluation/stageContextSelectors/index.js +4 -0
  38. package/dist/src/evaluation/stageContextSelectors/retrievalAuditRecordSelectors.js +54 -0
  39. package/dist/src/evaluation/stageContextSelectors/workflowInstructionPacketSelectors.js +51 -0
  40. package/dist/src/evaluation/targetImmutability/captureTargetSnapshot.js +208 -0
  41. package/dist/src/evaluation/targetImmutability/compareTargetSnapshots.js +56 -0
  42. package/dist/src/evaluation/targetImmutability/index.js +3 -0
  43. package/dist/src/evaluation/targetImmutability/types.js +1 -0
  44. package/dist/src/evaluation/targetImmutability/validateTargetImmutabilityConfig.js +130 -0
  45. package/dist/src/evaluation/upstreamArtifacts/artifactReadTypes.js +1 -0
  46. package/dist/src/evaluation/upstreamArtifacts/index.js +9 -0
  47. package/dist/src/evaluation/upstreamArtifacts/jsonTypes.js +1 -0
  48. package/dist/src/evaluation/upstreamArtifacts/myDevKitClassificationTypesV1.js +1 -0
  49. package/dist/src/evaluation/upstreamArtifacts/myDevKitContextArtifactsV1.js +1 -0
  50. package/dist/src/evaluation/upstreamArtifacts/myDevKitSemanticTypesV1.js +1 -0
  51. package/dist/src/evaluation/upstreamArtifacts/orchestratorContextReadinessResultV1.js +247 -0
  52. package/dist/src/evaluation/upstreamArtifacts/orchestratorWorkflowInstructionPacketV1.js +1 -0
  53. package/dist/src/evaluation/upstreamArtifacts/readImplementationContextPacketV1.js +9 -0
  54. package/dist/src/evaluation/upstreamArtifacts/readImplementationContextRetrievalReportV1.js +9 -0
  55. package/dist/src/evaluation/upstreamArtifacts/readJsonArtifact.js +53 -0
  56. package/dist/src/evaluation/upstreamArtifacts/readMyDevKitContextCapsuleV1.js +9 -0
  57. package/dist/src/evaluation/upstreamArtifacts/readMyDevKitRetrievalAuditRecordV1.js +9 -0
  58. package/dist/src/evaluation/upstreamArtifacts/readOrchestratorWorkflowInstructionPacketV1.js +9 -0
  59. package/dist/src/evaluation/upstreamArtifacts/readSupplementalContextTextFile.js +29 -0
  60. package/dist/src/evaluation/upstreamArtifacts/readTestContextPacketV1.js +9 -0
  61. package/dist/src/evaluation/upstreamArtifacts/readTestContextRetrievalReportV1.js +9 -0
  62. package/dist/src/evaluation/upstreamArtifacts/runtimeValidation.js +131 -0
  63. package/dist/src/evaluation/upstreamArtifacts/schemaVersion.js +32 -0
  64. package/dist/src/evaluation/upstreamArtifacts/supplementalContextTextParser.js +75 -0
  65. package/dist/src/evaluation/upstreamArtifacts/supplementalContextTypes.js +152 -0
  66. package/dist/src/evaluation/upstreamArtifacts/validateMyDevKitContextCapsuleV1.js +1208 -0
  67. package/dist/src/evaluation/upstreamArtifacts/validateMyDevKitRetrievalAuditRecordV1.js +112 -0
  68. package/dist/src/evaluation/upstreamArtifacts/validateOrchestratorWorkflowInstructionPacketV1.js +235 -0
  69. package/dist/src/evaluation/upstreamArtifacts/validateSupplementalContextDocumentV1.js +148 -0
  70. package/dist/src/experiments/plugins/contextStrategyComparison/executeV043StageContextStrategy.js +46 -0
  71. package/dist/src/experiments/plugins/contextStrategyComparison/index.js +9 -0
  72. package/dist/src/experiments/plugins/contextStrategyComparison/loadV043StrategyArtifacts.js +397 -0
  73. package/dist/src/experiments/plugins/contextStrategyComparison/plugin.js +39 -1
  74. package/dist/src/experiments/plugins/contextStrategyComparison/readV043FullWorkflowLibraryFixture.js +162 -0
  75. package/dist/src/experiments/plugins/contextStrategyComparison/resolveV043StrategyInputs.js +43 -0
  76. package/dist/src/experiments/plugins/contextStrategyComparison/resultMapping.js +3 -0
  77. package/dist/src/experiments/plugins/contextStrategyComparison/runV043StageContextStrategyWithAssurance.js +205 -0
  78. package/dist/src/experiments/plugins/contextStrategyComparison/v043FullWorkflowLibraryFixture.js +1 -0
  79. package/dist/src/experiments/plugins/contextStrategyComparison/v043RunAssuranceTypes.js +1 -0
  80. package/dist/src/experiments/plugins/contextStrategyComparison/v043StrategyExecutionTypes.js +1 -0
  81. package/dist/src/experiments/plugins/contextStrategyComparison/v043StrategyIds.js +13 -0
  82. package/dist/src/experiments/plugins/contextStrategyComparison/v043StrategyInputContracts.js +1 -0
  83. package/dist/src/experiments/plugins/contextStrategyComparison/validateV043RunAssuranceConfig.js +59 -0
  84. package/dist/src/experiments/plugins/contextStrategyComparison/validateV043StrategyInput.js +266 -0
  85. package/dist/src/report/experiments/buildContextStrategyComparisonV043Report.js +520 -0
  86. package/dist/src/report/experiments/buildPluginExperimentReport.js +21 -6
  87. package/dist/src/report/experiments/contextStrategyComparisonV043ReportModel.js +1 -0
  88. package/dist/src/report/experiments/index.js +4 -0
  89. package/dist/src/report/experiments/renderContextStrategyComparisonV043Html.js +296 -0
  90. package/dist/src/report/experiments/renderPluginExperimentReportHtml.js +3 -0
  91. package/dist/src/report/experiments/renderPluginExperimentReportText.js +292 -0
  92. package/dist/src/report/experiments/writePluginExperimentReports.js +3 -0
  93. package/dist/src/securityValidation/attackScenarios/scenarios/secretLeakageScenario.js +215 -9
  94. package/docs/METRICS.md +84 -10
  95. package/package.json +2 -2
  96. package/tests/fixtures/full-workflow-library/complete-v1.0.0.json +24 -0
  97. package/tests/fixtures/full-workflow-library/future-minor-v1.1.0-additive.json +25 -0
  98. package/tests/fixtures/stage-context-expectations/complete-v1.0.0.json +230 -0
  99. package/tests/fixtures/stage-context-expectations/future-minor-v1.1.0-additive.json +232 -0
  100. package/tests/fixtures/stage-context-expectations/invalid/malformed-json.txt +1 -0
  101. package/tests/fixtures/stage-context-expectations/invalid/non-object-root.json +1 -0
  102. package/tests/fixtures/stage-context-expectations/minimal-v1.0.0.json +18 -0
  103. package/tests/fixtures/upstream-artifacts/invalid/malformed-json.txt +1 -0
  104. package/tests/fixtures/upstream-artifacts/invalid/non-object-root.json +1 -0
  105. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/context-capsule/complete-v1.0.0.json +504 -0
  106. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/context-capsule/future-minor-v1.1.0-additive.json +955 -0
  107. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/retrieval-audit-record/complete-v1.0.0.json +190 -0
  108. package/tests/fixtures/upstream-artifacts/my-dev-kit/1.10.2/retrieval-audit-record/future-minor-v1.1.0-additive.json +327 -0
  109. package/tests/fixtures/upstream-artifacts/my-dev-kit-1.10.2-identity/PROVENANCE.txt +13 -0
  110. package/tests/fixtures/upstream-artifacts/my-dev-kit-1.10.2-identity/context-capsule.json +7874 -0
  111. package/tests/fixtures/upstream-artifacts/my-dev-kit-1.10.2-identity/retrieval-audit-record.json +1076 -0
  112. package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.1/workflow-instruction-packet/complete-v1.0.0.json +160 -0
  113. package/tests/fixtures/upstream-artifacts/my-dev-kit-orchestrator/1.2.1/workflow-instruction-packet/future-minor-v1.1.0-additive.json +186 -0
@@ -21,6 +21,9 @@ export function mapLegacyArtifactsToExperimentRun(args) {
21
21
  warnings,
22
22
  failures,
23
23
  legacyArtifacts: args.legacyArtifacts,
24
+ v043StageContextExecutions: args.v043StageContextExecutions,
25
+ v043StageContextEvaluations: args.v043StageContextEvaluations,
26
+ v043StageContextRunAssurance: args.v043StageContextRunAssurance,
24
27
  metadata: {
25
28
  pluginName: "Context Strategy Comparison",
26
29
  pluginSchemaVersion: "1.0.0",
@@ -0,0 +1,205 @@
1
+ import { captureTargetSnapshot, compareTargetSnapshots } from "../../../evaluation/targetImmutability/index.js";
2
+ import { calculateStageContextDeterminism } from "../../../evaluation/stageContextDeterminism/index.js";
3
+ import { buildProducerReadinessBridgeInputFromCombinedPayload, evaluateProducerReadinessBridge, evaluateV043StageContextExecution } from "../../../evaluation/stageContextMetrics/index.js";
4
+ import { executeV043StageContextStrategy } from "./executeV043StageContextStrategy.js";
5
+ async function buildRunWithTargetImmutability(targetConfig, input) {
6
+ if (targetConfig === undefined) {
7
+ const execution = await executeV043StageContextStrategy(input);
8
+ return {
9
+ execution,
10
+ targetImmutability: {
11
+ availability: "unavailable",
12
+ comparison: null,
13
+ reason: "Target immutability configuration was not supplied for this strategy run."
14
+ }
15
+ };
16
+ }
17
+ const beforeResult = await captureTargetSnapshot(targetConfig);
18
+ const execution = await executeV043StageContextStrategy(input);
19
+ const afterResult = await captureTargetSnapshot(targetConfig);
20
+ if (!beforeResult.ok && !afterResult.ok) {
21
+ return {
22
+ execution,
23
+ targetImmutability: {
24
+ availability: "unavailable",
25
+ comparison: null,
26
+ reason: "Target immutability could not be evaluated because a target snapshot failed.",
27
+ beforeFailure: beforeResult,
28
+ afterFailure: afterResult
29
+ }
30
+ };
31
+ }
32
+ if (!beforeResult.ok) {
33
+ return {
34
+ execution,
35
+ targetImmutability: {
36
+ availability: "unavailable",
37
+ comparison: null,
38
+ reason: "Target immutability could not be evaluated because a target snapshot failed.",
39
+ beforeFailure: beforeResult
40
+ }
41
+ };
42
+ }
43
+ if (!afterResult.ok) {
44
+ return {
45
+ execution,
46
+ targetImmutability: {
47
+ availability: "unavailable",
48
+ comparison: null,
49
+ reason: "Target immutability could not be evaluated because a target snapshot failed.",
50
+ afterFailure: afterResult
51
+ }
52
+ };
53
+ }
54
+ const comparison = compareTargetSnapshots(beforeResult.snapshot, afterResult.snapshot);
55
+ return {
56
+ execution,
57
+ targetImmutability: { availability: "available", comparison, reason: null }
58
+ };
59
+ }
60
+ // v0.4.4 Batch 3: computed exactly once per run, immediately after execution, from the
61
+ // already-loaded execution payload -- never rereads artifacts, never reruns the strategy.
62
+ function buildProducerReadinessBridgeResult(execution) {
63
+ if (execution.status !== "completed" || execution.strategyId !== "combined-bounded-stage-context")
64
+ return null;
65
+ const payload = execution.payload;
66
+ const bridgeInput = buildProducerReadinessBridgeInputFromCombinedPayload(payload, execution.expectations);
67
+ return evaluateProducerReadinessBridge(bridgeInput);
68
+ }
69
+ function computeStatus(issues, config) {
70
+ if (issues.length > 0)
71
+ return "failed";
72
+ const anyCheckApplies = config.targetImmutability !== undefined || config.repeatCount > 1;
73
+ return anyCheckApplies ? "passed" : "not-applicable";
74
+ }
75
+ export async function runV043StageContextStrategyWithAssurance(input, config) {
76
+ const runRecords = [];
77
+ const determinismCandidates = [];
78
+ const issues = [];
79
+ let primaryExecution;
80
+ let primaryEvaluation;
81
+ let primaryProducerReadinessBridge = null;
82
+ try {
83
+ for (let runNumber = 1; runNumber <= config.repeatCount; runNumber += 1) {
84
+ const { execution, targetImmutability } = await buildRunWithTargetImmutability(config.targetImmutability, input);
85
+ const evaluation = evaluateV043StageContextExecution(execution, { targetImmutability });
86
+ const producerReadinessBridge = buildProducerReadinessBridgeResult(execution);
87
+ if (runNumber === 1) {
88
+ primaryExecution = execution;
89
+ primaryEvaluation = evaluation;
90
+ primaryProducerReadinessBridge = producerReadinessBridge;
91
+ }
92
+ runRecords.push({
93
+ runNumber,
94
+ executionStatus: execution.status,
95
+ evaluationStatus: evaluation.status,
96
+ targetImmutability,
97
+ producerReadinessBridge
98
+ });
99
+ determinismCandidates.push({
100
+ runNumber,
101
+ value: { execution, evaluation, targetImmutability, producerReadinessBridge }
102
+ });
103
+ if (execution.status !== "completed") {
104
+ issues.push({
105
+ code: "EXECUTION_NOT_COMPLETED",
106
+ runNumber,
107
+ fieldPath: `runs[${runNumber}].execution.status`,
108
+ message: "Strategy execution did not complete successfully."
109
+ });
110
+ }
111
+ if (evaluation.status !== "completed") {
112
+ issues.push({
113
+ code: "EVALUATION_NOT_COMPLETED",
114
+ runNumber,
115
+ fieldPath: `runs[${runNumber}].evaluation.status`,
116
+ message: "Stage-context evaluation did not complete successfully."
117
+ });
118
+ }
119
+ if (config.targetImmutability !== undefined && targetImmutability.availability === "unavailable") {
120
+ issues.push({
121
+ code: "TARGET_SNAPSHOT_UNAVAILABLE",
122
+ runNumber,
123
+ fieldPath: `runs[${runNumber}].targetImmutability`,
124
+ message: "Target immutability assurance is unavailable for this run."
125
+ });
126
+ }
127
+ if (targetImmutability.availability === "available" && targetImmutability.comparison.status === "mutated") {
128
+ for (const mutation of targetImmutability.comparison.mutations) {
129
+ issues.push({
130
+ code: "TARGET_MUTATION_DETECTED",
131
+ runNumber,
132
+ fieldPath: `runs[${runNumber}].targetImmutability.${mutation.fieldPath}`,
133
+ message: `Target mutation detected at "${mutation.fieldPath}".`
134
+ });
135
+ }
136
+ }
137
+ }
138
+ const determinism = calculateStageContextDeterminism(determinismCandidates);
139
+ if (config.repeatCount > 1 && determinism.availability === "unavailable") {
140
+ issues.push({
141
+ code: "DETERMINISM_UNAVAILABLE",
142
+ runNumber: null,
143
+ fieldPath: "determinism",
144
+ message: "Repeated-run determinism could not be evaluated."
145
+ });
146
+ }
147
+ if (determinism.availability === "available" && determinism.deterministic === false) {
148
+ for (const mismatchRunNumber of determinism.mismatchRunNumbers) {
149
+ issues.push({
150
+ code: "NONDETERMINISTIC_RESULT",
151
+ runNumber: mismatchRunNumber,
152
+ fieldPath: `determinism.runs[${mismatchRunNumber}]`,
153
+ message: `Run ${mismatchRunNumber} differs from the baseline run.`
154
+ });
155
+ }
156
+ }
157
+ return {
158
+ strategyId: input.strategyId,
159
+ status: computeStatus(issues, config),
160
+ repeatCount: config.repeatCount,
161
+ primaryExecution: primaryExecution,
162
+ primaryEvaluation: primaryEvaluation,
163
+ primaryProducerReadinessBridge,
164
+ runRecords,
165
+ determinism,
166
+ issues
167
+ };
168
+ }
169
+ catch {
170
+ const fallbackExecution = primaryExecution ?? { status: "failed", strategyId: null, input, issues: [] };
171
+ const fallbackEvaluation = primaryEvaluation ?? {
172
+ status: "failed",
173
+ strategyId: null,
174
+ executionStatus: "failed",
175
+ reason: "Unexpected v0.4.3 stage-context run-assurance failure."
176
+ };
177
+ const fallbackDeterminism = {
178
+ availability: "unavailable",
179
+ repeatCount: config.repeatCount,
180
+ deterministic: null,
181
+ baselineSha256: null,
182
+ runDigests: [],
183
+ mismatchRunNumbers: [],
184
+ reason: "Unexpected v0.4.3 stage-context run-assurance failure prevented determinism evaluation."
185
+ };
186
+ return {
187
+ strategyId: input.strategyId,
188
+ status: "failed",
189
+ repeatCount: config.repeatCount,
190
+ primaryExecution: fallbackExecution,
191
+ primaryEvaluation: fallbackEvaluation,
192
+ primaryProducerReadinessBridge,
193
+ runRecords,
194
+ determinism: fallbackDeterminism,
195
+ issues: [
196
+ {
197
+ code: "UNEXPECTED_ASSURANCE_ERROR",
198
+ runNumber: null,
199
+ fieldPath: "assurance",
200
+ message: "Unexpected v0.4.3 stage-context run-assurance failure."
201
+ }
202
+ ]
203
+ };
204
+ }
205
+ }
@@ -0,0 +1,13 @@
1
+ export const EXISTING_CONTEXT_STRATEGY_IDS = ["raw-full-file", "my-dev-kit-guided"];
2
+ export const V043_STAGE_CONTEXT_STRATEGY_IDS = [
3
+ "architecture-context-only",
4
+ "architecture-plus-implementation-refresh",
5
+ "architecture-plus-implementation-and-test-refresh",
6
+ "full-workflow-library",
7
+ "bounded-workflow-instruction-packet",
8
+ "combined-bounded-stage-context"
9
+ ];
10
+ export const CONTEXT_STRATEGY_IDS_WITH_V043 = [
11
+ ...EXISTING_CONTEXT_STRATEGY_IDS,
12
+ ...V043_STAGE_CONTEXT_STRATEGY_IDS
13
+ ];
@@ -0,0 +1,59 @@
1
+ import { validateTargetImmutabilityConfig } from "../../../evaluation/targetImmutability/index.js";
2
+ const ALLOWED_KEYS = ["repeatCount", "targetImmutability"];
3
+ function isPlainObject(value) {
4
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5
+ }
6
+ export function validateV043RunAssuranceConfig(value) {
7
+ if (value === undefined) {
8
+ return { ok: true, config: { repeatCount: 1 } };
9
+ }
10
+ if (!isPlainObject(value)) {
11
+ return {
12
+ ok: false,
13
+ issues: [{ code: "NON_OBJECT_CONFIG", fieldPath: "", message: "v0.4.3 run-assurance config must be an object." }]
14
+ };
15
+ }
16
+ const root = value;
17
+ const issues = [];
18
+ for (const key of Object.keys(root)) {
19
+ if (!ALLOWED_KEYS.includes(key)) {
20
+ issues.push({ code: "UNKNOWN_CONFIG_FIELD", fieldPath: key, message: `"${key}" is not a recognized field.` });
21
+ }
22
+ }
23
+ let repeatCount = 1;
24
+ if (root.repeatCount !== undefined) {
25
+ const candidate = root.repeatCount;
26
+ if (typeof candidate !== "number" || !Number.isInteger(candidate) || candidate < 1 || candidate > 10) {
27
+ issues.push({
28
+ code: "INVALID_REPEAT_COUNT",
29
+ fieldPath: "repeatCount",
30
+ message: "repeatCount must be an integer from 1 through 10."
31
+ });
32
+ }
33
+ else {
34
+ repeatCount = candidate;
35
+ }
36
+ }
37
+ let targetImmutability;
38
+ if (root.targetImmutability !== undefined) {
39
+ const result = validateTargetImmutabilityConfig(root.targetImmutability);
40
+ if (!result.ok) {
41
+ issues.push({
42
+ code: "INVALID_TARGET_IMMUTABILITY_CONFIG",
43
+ fieldPath: "targetImmutability",
44
+ message: "targetImmutability configuration is invalid.",
45
+ details: result.issues
46
+ });
47
+ }
48
+ else {
49
+ targetImmutability = result.config;
50
+ }
51
+ }
52
+ if (issues.length > 0) {
53
+ return { ok: false, issues };
54
+ }
55
+ return {
56
+ ok: true,
57
+ config: targetImmutability !== undefined ? { repeatCount, targetImmutability } : { repeatCount }
58
+ };
59
+ }
@@ -0,0 +1,266 @@
1
+ import { V043_STAGE_CONTEXT_STRATEGY_IDS } from "./v043StrategyIds.js";
2
+ const CONTEXT_ROLE_VALUES = ["architecture", "implementation", "test-implementation"];
3
+ const COMBINED_ENTRY_ALLOWED_KEYS = ["role", "contextCapsulePath", "retrievalAuditRecordPath"];
4
+ const STRATEGY_CONTRACTS = {
5
+ "architecture-context-only": {
6
+ fields: [
7
+ { name: "expectationsPath", kind: "required-path" },
8
+ { name: "architectureContextCapsulePath", kind: "required-path" },
9
+ { name: "architectureRetrievalAuditRecordPath", kind: "optional-path" }
10
+ ]
11
+ },
12
+ "architecture-plus-implementation-refresh": {
13
+ fields: [
14
+ { name: "expectationsPath", kind: "required-path" },
15
+ { name: "architectureContextCapsulePath", kind: "required-path" },
16
+ { name: "architectureRetrievalAuditRecordPath", kind: "optional-path" },
17
+ { name: "implementationContextCapsulePath", kind: "required-path" },
18
+ { name: "implementationRetrievalAuditRecordPath", kind: "optional-path" }
19
+ ]
20
+ },
21
+ "architecture-plus-implementation-and-test-refresh": {
22
+ fields: [
23
+ { name: "expectationsPath", kind: "required-path" },
24
+ { name: "architectureContextCapsulePath", kind: "required-path" },
25
+ { name: "architectureRetrievalAuditRecordPath", kind: "optional-path" },
26
+ { name: "implementationContextCapsulePath", kind: "required-path" },
27
+ { name: "implementationRetrievalAuditRecordPath", kind: "optional-path" },
28
+ { name: "testImplementationContextCapsulePath", kind: "required-path" },
29
+ { name: "testImplementationRetrievalAuditRecordPath", kind: "optional-path" }
30
+ ]
31
+ },
32
+ "full-workflow-library": {
33
+ fields: [
34
+ { name: "expectationsPath", kind: "required-path" },
35
+ { name: "fullWorkflowLibraryFixturePath", kind: "required-path" }
36
+ ]
37
+ },
38
+ "bounded-workflow-instruction-packet": {
39
+ fields: [
40
+ { name: "expectationsPath", kind: "required-path" },
41
+ { name: "workflowInstructionPacketPath", kind: "required-path" }
42
+ ]
43
+ },
44
+ "combined-bounded-stage-context": {
45
+ fields: [
46
+ { name: "expectationsPath", kind: "required-path" },
47
+ { name: "contextArtifacts", kind: "required-array" },
48
+ { name: "workflowInstructionPacketPath", kind: "required-path" },
49
+ { name: "implementationContextPacketPath", kind: "optional-path" },
50
+ { name: "implementationContextRetrievalReportPath", kind: "optional-path" },
51
+ { name: "testContextPacketPath", kind: "optional-path" },
52
+ { name: "testContextRetrievalReportPath", kind: "optional-path" },
53
+ { name: "readiness", kind: "optional-object" }
54
+ ]
55
+ }
56
+ };
57
+ function isPlainObject(value) {
58
+ return typeof value === "object" && value !== null && !Array.isArray(value);
59
+ }
60
+ export function validateV043StrategyInput(value) {
61
+ if (!isPlainObject(value)) {
62
+ return {
63
+ ok: false,
64
+ issues: [{ code: "NON_OBJECT_INPUT", fieldPath: "", message: "Strategy input must be an object." }]
65
+ };
66
+ }
67
+ const root = value;
68
+ const issues = [];
69
+ let strategyId;
70
+ if (root.strategyId === undefined) {
71
+ issues.push({ code: "MISSING_REQUIRED_FIELD", fieldPath: "strategyId", message: "strategyId is required." });
72
+ }
73
+ else if (typeof root.strategyId !== "string") {
74
+ issues.push({ code: "INVALID_FIELD_TYPE", fieldPath: "strategyId", message: "strategyId must be a string." });
75
+ }
76
+ else if (!V043_STAGE_CONTEXT_STRATEGY_IDS.includes(root.strategyId)) {
77
+ issues.push({
78
+ code: "INVALID_STRATEGY_ID",
79
+ fieldPath: "strategyId",
80
+ message: `strategyId "${root.strategyId}" is not a valid v0.4.3 stage-context strategy id.`
81
+ });
82
+ }
83
+ else {
84
+ strategyId = root.strategyId;
85
+ }
86
+ if (strategyId === undefined) {
87
+ return { ok: false, issues };
88
+ }
89
+ const contract = STRATEGY_CONTRACTS[strategyId];
90
+ const allowedKeys = ["strategyId", ...contract.fields.map((field) => field.name)];
91
+ for (const key of Object.keys(root)) {
92
+ if (!allowedKeys.includes(key)) {
93
+ issues.push({
94
+ code: "UNKNOWN_INPUT_FIELD",
95
+ fieldPath: key,
96
+ message: `"${key}" is not a recognized field for strategy "${strategyId}".`
97
+ });
98
+ }
99
+ }
100
+ for (const field of contract.fields) {
101
+ if (field.kind !== "optional-path" && field.kind !== "optional-object" && root[field.name] === undefined) {
102
+ issues.push({
103
+ code: "MISSING_REQUIRED_FIELD",
104
+ fieldPath: field.name,
105
+ message: `"${field.name}" is required for strategy "${strategyId}".`
106
+ });
107
+ }
108
+ }
109
+ for (const field of contract.fields) {
110
+ const fieldValue = root[field.name];
111
+ if (fieldValue === undefined)
112
+ continue;
113
+ if (field.kind === "required-array") {
114
+ if (!Array.isArray(fieldValue)) {
115
+ issues.push({
116
+ code: "INVALID_FIELD_TYPE",
117
+ fieldPath: field.name,
118
+ message: `"${field.name}" must be an array.`
119
+ });
120
+ }
121
+ }
122
+ else if (field.kind === "optional-object") {
123
+ if (!isPlainObject(fieldValue)) {
124
+ issues.push({
125
+ code: "INVALID_FIELD_TYPE",
126
+ fieldPath: field.name,
127
+ message: `"${field.name}" must be an object.`
128
+ });
129
+ }
130
+ }
131
+ else if (typeof fieldValue !== "string") {
132
+ issues.push({
133
+ code: "INVALID_FIELD_TYPE",
134
+ fieldPath: field.name,
135
+ message: `"${field.name}" must be a string.`
136
+ });
137
+ }
138
+ }
139
+ for (const field of contract.fields) {
140
+ if (field.kind === "required-array" || field.kind === "optional-object")
141
+ continue;
142
+ const fieldValue = root[field.name];
143
+ if (typeof fieldValue === "string" && fieldValue.length === 0) {
144
+ issues.push({ code: "EMPTY_PATH", fieldPath: field.name, message: `"${field.name}" must not be empty.` });
145
+ }
146
+ }
147
+ if (strategyId === "combined-bounded-stage-context" && Array.isArray(root.contextArtifacts)) {
148
+ const contextArtifacts = root.contextArtifacts;
149
+ if (contextArtifacts.length === 0) {
150
+ issues.push({
151
+ code: "EMPTY_CONTEXT_ARTIFACT_SET",
152
+ fieldPath: "contextArtifacts",
153
+ message: "contextArtifacts must contain at least one entry."
154
+ });
155
+ }
156
+ else if (contextArtifacts.length > 3) {
157
+ issues.push({
158
+ code: "TOO_MANY_CONTEXT_ARTIFACTS",
159
+ fieldPath: "contextArtifacts",
160
+ message: "contextArtifacts must contain at most three entries."
161
+ });
162
+ }
163
+ for (let index = 0; index < contextArtifacts.length; index += 1) {
164
+ const entry = contextArtifacts[index];
165
+ if (!isPlainObject(entry)) {
166
+ issues.push({
167
+ code: "INVALID_FIELD_TYPE",
168
+ fieldPath: `contextArtifacts[${index}]`,
169
+ message: `contextArtifacts[${index}] must be an object.`
170
+ });
171
+ continue;
172
+ }
173
+ for (const key of Object.keys(entry)) {
174
+ if (!COMBINED_ENTRY_ALLOWED_KEYS.includes(key)) {
175
+ issues.push({
176
+ code: "UNKNOWN_INPUT_FIELD",
177
+ fieldPath: `contextArtifacts[${index}].${key}`,
178
+ message: `"${key}" is not a recognized field for a combined context artifact entry.`
179
+ });
180
+ }
181
+ }
182
+ }
183
+ for (let index = 0; index < contextArtifacts.length; index += 1) {
184
+ const entry = contextArtifacts[index];
185
+ if (!isPlainObject(entry))
186
+ continue;
187
+ if (entry.role === undefined) {
188
+ issues.push({
189
+ code: "MISSING_REQUIRED_FIELD",
190
+ fieldPath: `contextArtifacts[${index}].role`,
191
+ message: `contextArtifacts[${index}].role is required.`
192
+ });
193
+ }
194
+ if (entry.contextCapsulePath === undefined) {
195
+ issues.push({
196
+ code: "MISSING_REQUIRED_FIELD",
197
+ fieldPath: `contextArtifacts[${index}].contextCapsulePath`,
198
+ message: `contextArtifacts[${index}].contextCapsulePath is required.`
199
+ });
200
+ }
201
+ }
202
+ for (let index = 0; index < contextArtifacts.length; index += 1) {
203
+ const entry = contextArtifacts[index];
204
+ if (!isPlainObject(entry))
205
+ continue;
206
+ if (entry.role !== undefined && (typeof entry.role !== "string" || !CONTEXT_ROLE_VALUES.includes(entry.role))) {
207
+ issues.push({
208
+ code: "INVALID_CONTEXT_ROLE",
209
+ fieldPath: `contextArtifacts[${index}].role`,
210
+ message: `contextArtifacts[${index}].role "${entry.role}" is not a valid context role.`
211
+ });
212
+ }
213
+ if (entry.contextCapsulePath !== undefined && typeof entry.contextCapsulePath !== "string") {
214
+ issues.push({
215
+ code: "INVALID_FIELD_TYPE",
216
+ fieldPath: `contextArtifacts[${index}].contextCapsulePath`,
217
+ message: `contextArtifacts[${index}].contextCapsulePath must be a string.`
218
+ });
219
+ }
220
+ if (entry.retrievalAuditRecordPath !== undefined && typeof entry.retrievalAuditRecordPath !== "string") {
221
+ issues.push({
222
+ code: "INVALID_FIELD_TYPE",
223
+ fieldPath: `contextArtifacts[${index}].retrievalAuditRecordPath`,
224
+ message: `contextArtifacts[${index}].retrievalAuditRecordPath must be a string.`
225
+ });
226
+ }
227
+ }
228
+ for (let index = 0; index < contextArtifacts.length; index += 1) {
229
+ const entry = contextArtifacts[index];
230
+ if (!isPlainObject(entry))
231
+ continue;
232
+ if (typeof entry.contextCapsulePath === "string" && entry.contextCapsulePath.length === 0) {
233
+ issues.push({
234
+ code: "EMPTY_PATH",
235
+ fieldPath: `contextArtifacts[${index}].contextCapsulePath`,
236
+ message: `contextArtifacts[${index}].contextCapsulePath must not be empty.`
237
+ });
238
+ }
239
+ if (typeof entry.retrievalAuditRecordPath === "string" && entry.retrievalAuditRecordPath.length === 0) {
240
+ issues.push({
241
+ code: "EMPTY_PATH",
242
+ fieldPath: `contextArtifacts[${index}].retrievalAuditRecordPath`,
243
+ message: `contextArtifacts[${index}].retrievalAuditRecordPath must not be empty.`
244
+ });
245
+ }
246
+ }
247
+ const seenRoles = new Set();
248
+ for (let index = 0; index < contextArtifacts.length; index += 1) {
249
+ const entry = contextArtifacts[index];
250
+ if (!isPlainObject(entry) || typeof entry.role !== "string")
251
+ continue;
252
+ if (seenRoles.has(entry.role)) {
253
+ issues.push({
254
+ code: "DUPLICATE_CONTEXT_ROLE",
255
+ fieldPath: `contextArtifacts[${index}].role`,
256
+ message: `contextArtifacts[${index}].role "${entry.role}" is duplicated.`
257
+ });
258
+ }
259
+ seenRoles.add(entry.role);
260
+ }
261
+ }
262
+ if (issues.length > 0) {
263
+ return { ok: false, issues };
264
+ }
265
+ return { ok: true, input: value };
266
+ }