@danmoisan/drm-copilot-mcp 1.0.20 → 1.0.22
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/out/mcp-server.js +1687 -210
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/MEMORY.md +5 -1
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_commit_push_memory_before_pr.md +48 -2
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_no_sendmessage_tool.md +35 -0
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_worktree_isolation_branches_from_main.md +45 -0
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +238 -0
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +149 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +23 -11
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +259 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +499 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate-helpers.ps1 +302 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +359 -0
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +244 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +379 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConfig.psm1 +491 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +490 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusGlob.psm1 +429 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusValidation.psm1 +366 -0
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +184 -0
- package/resources/claude-customizations/.claude/settings.json +25 -0
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +148 -0
- package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +93 -0
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +960 -0
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +420 -0
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +176 -0
- package/resources/claude-customizations/.claude/skills/parallel-run/SKILL.md +56 -0
- package/resources/claude-customizations/pack-manifests/core.json +19 -1
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +4 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +4 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +4 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +4 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +4 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +4 -0
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/config/orchestration-routing.json +22 -0
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +29 -0
package/out/mcp-server.js
CHANGED
|
@@ -1796,13 +1796,13 @@ var require_code2 = __commonJS({
|
|
|
1796
1796
|
const valid = gen.name("valid");
|
|
1797
1797
|
if (it.allErrors) {
|
|
1798
1798
|
const validArr = gen.let("valid", true);
|
|
1799
|
-
|
|
1799
|
+
validateItems2(() => gen.assign(validArr, false));
|
|
1800
1800
|
return validArr;
|
|
1801
1801
|
}
|
|
1802
1802
|
gen.var(valid, true);
|
|
1803
|
-
|
|
1803
|
+
validateItems2(() => gen.break());
|
|
1804
1804
|
return valid;
|
|
1805
|
-
function
|
|
1805
|
+
function validateItems2(notValid) {
|
|
1806
1806
|
const len = gen.const("len", (0, codegen_1._)`${data}.length`);
|
|
1807
1807
|
gen.forRange("i", 0, len, (i) => {
|
|
1808
1808
|
cxt.subschema({
|
|
@@ -3646,7 +3646,12 @@ var require_fast_uri = __commonJS({
|
|
|
3646
3646
|
}
|
|
3647
3647
|
function resolve4(baseURI, relativeURI, options) {
|
|
3648
3648
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3649
|
-
const
|
|
3649
|
+
const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions);
|
|
3650
|
+
const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions);
|
|
3651
|
+
if (baseMalformed || relativeMalformed) {
|
|
3652
|
+
throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
|
|
3653
|
+
}
|
|
3654
|
+
const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
|
|
3650
3655
|
schemelessOptions.skipEscape = true;
|
|
3651
3656
|
return serialize(resolved, schemelessOptions);
|
|
3652
3657
|
}
|
|
@@ -3772,6 +3777,7 @@ var require_fast_uri = __commonJS({
|
|
|
3772
3777
|
}
|
|
3773
3778
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
3774
3779
|
var AUTHORITY_PREFIX = /^(?:[^#/:?]+:)?\/\/([^/?#]*)/;
|
|
3780
|
+
var AUTHORITY_INTRODUCER_REGION = /^(?:[^#/:?]+:)?([/\\\t\n\r]*)/;
|
|
3775
3781
|
function getParseError(parsed, matches) {
|
|
3776
3782
|
if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
|
|
3777
3783
|
return 'URI path must start with "/" when authority is present.';
|
|
@@ -3806,6 +3812,20 @@ var require_fast_uri = __commonJS({
|
|
|
3806
3812
|
parsed.error = "URI authority must not contain a literal backslash.";
|
|
3807
3813
|
malformedAuthorityOrPort = true;
|
|
3808
3814
|
}
|
|
3815
|
+
const introducerMatch = uri.match(AUTHORITY_INTRODUCER_REGION);
|
|
3816
|
+
if (introducerMatch !== null) {
|
|
3817
|
+
const region = introducerMatch[1];
|
|
3818
|
+
const normalizedRegion = region.replace(/[\t\n\r]/g, "");
|
|
3819
|
+
if (normalizedRegion.length >= 2) {
|
|
3820
|
+
if (normalizedRegion.slice(0, 2) !== "//") {
|
|
3821
|
+
parsed.error = parsed.error || "URI authority must not contain a literal backslash.";
|
|
3822
|
+
malformedAuthorityOrPort = true;
|
|
3823
|
+
} else if (region.length !== normalizedRegion.length) {
|
|
3824
|
+
parsed.error = parsed.error || "URI authority introducer must not contain whitespace.";
|
|
3825
|
+
malformedAuthorityOrPort = true;
|
|
3826
|
+
}
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3809
3829
|
const matches = uri.match(URI_PARSE);
|
|
3810
3830
|
if (matches) {
|
|
3811
3831
|
parsed.scheme = matches[1];
|
|
@@ -5226,10 +5246,10 @@ var require_additionalItems = __commonJS({
|
|
|
5226
5246
|
cxt.pass((0, codegen_1._)`${len} <= ${items.length}`);
|
|
5227
5247
|
} else if (typeof schema == "object" && !(0, util_1.alwaysValidSchema)(it, schema)) {
|
|
5228
5248
|
const valid = gen.var("valid", (0, codegen_1._)`${len} <= ${items.length}`);
|
|
5229
|
-
gen.if((0, codegen_1.not)(valid), () =>
|
|
5249
|
+
gen.if((0, codegen_1.not)(valid), () => validateItems2(valid));
|
|
5230
5250
|
cxt.ok(valid);
|
|
5231
5251
|
}
|
|
5232
|
-
function
|
|
5252
|
+
function validateItems2(valid) {
|
|
5233
5253
|
gen.forRange("i", items.length, len, (i) => {
|
|
5234
5254
|
cxt.subschema({ keyword, dataProp: i, dataPropType: util_1.Type.Num }, valid);
|
|
5235
5255
|
if (!it.allErrors)
|
|
@@ -5401,7 +5421,7 @@ var require_contains = __commonJS({
|
|
|
5401
5421
|
it.items = true;
|
|
5402
5422
|
const valid = gen.name("valid");
|
|
5403
5423
|
if (max === void 0 && min === 1) {
|
|
5404
|
-
|
|
5424
|
+
validateItems2(valid, () => gen.if(valid, () => gen.break()));
|
|
5405
5425
|
} else if (min === 0) {
|
|
5406
5426
|
gen.let(valid, true);
|
|
5407
5427
|
if (max !== void 0)
|
|
@@ -5414,9 +5434,9 @@ var require_contains = __commonJS({
|
|
|
5414
5434
|
function validateItemsWithCount() {
|
|
5415
5435
|
const schValid = gen.name("_valid");
|
|
5416
5436
|
const count = gen.let("count", 0);
|
|
5417
|
-
|
|
5437
|
+
validateItems2(schValid, () => gen.if(schValid, () => checkLimits(count)));
|
|
5418
5438
|
}
|
|
5419
|
-
function
|
|
5439
|
+
function validateItems2(_valid, block) {
|
|
5420
5440
|
gen.forRange("i", 0, len, (i) => {
|
|
5421
5441
|
cxt.subschema({
|
|
5422
5442
|
keyword: "contains",
|
|
@@ -8970,13 +8990,13 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
|
8970
8990
|
}
|
|
8971
8991
|
return propValues;
|
|
8972
8992
|
});
|
|
8973
|
-
const
|
|
8993
|
+
const isObject15 = isObject;
|
|
8974
8994
|
const catchall = def.catchall;
|
|
8975
8995
|
let value;
|
|
8976
8996
|
inst._zod.parse = (payload, ctx) => {
|
|
8977
8997
|
value ?? (value = _normalized.value);
|
|
8978
8998
|
const input = payload.value;
|
|
8979
|
-
if (!
|
|
8999
|
+
if (!isObject15(input)) {
|
|
8980
9000
|
payload.issues.push({
|
|
8981
9001
|
expected: "object",
|
|
8982
9002
|
code: "invalid_type",
|
|
@@ -9103,7 +9123,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
|
|
|
9103
9123
|
return (payload, ctx) => fn(shape, payload, ctx);
|
|
9104
9124
|
};
|
|
9105
9125
|
let fastpass;
|
|
9106
|
-
const
|
|
9126
|
+
const isObject15 = isObject;
|
|
9107
9127
|
const jit = !globalConfig.jitless;
|
|
9108
9128
|
const allowsEval2 = allowsEval;
|
|
9109
9129
|
const fastEnabled = jit && allowsEval2.value;
|
|
@@ -9112,7 +9132,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
|
|
|
9112
9132
|
inst._zod.parse = (payload, ctx) => {
|
|
9113
9133
|
value ?? (value = _normalized.value);
|
|
9114
9134
|
const input = payload.value;
|
|
9115
|
-
if (!
|
|
9135
|
+
if (!isObject15(input)) {
|
|
9116
9136
|
payload.issues.push({
|
|
9117
9137
|
expected: "object",
|
|
9118
9138
|
code: "invalid_type",
|
|
@@ -15069,16 +15089,7 @@ var Server = class extends Protocol {
|
|
|
15069
15089
|
if (!methodSchema) {
|
|
15070
15090
|
throw new Error("Schema is missing a method literal");
|
|
15071
15091
|
}
|
|
15072
|
-
|
|
15073
|
-
if (isZ4Schema(methodSchema)) {
|
|
15074
|
-
const v4Schema = methodSchema;
|
|
15075
|
-
const v4Def = v4Schema._zod?.def;
|
|
15076
|
-
methodValue = v4Def?.value ?? v4Schema.value;
|
|
15077
|
-
} else {
|
|
15078
|
-
const v3Schema = methodSchema;
|
|
15079
|
-
const legacyDef = v3Schema._def;
|
|
15080
|
-
methodValue = legacyDef?.value ?? v3Schema.value;
|
|
15081
|
-
}
|
|
15092
|
+
const methodValue = getLiteralValue(methodSchema);
|
|
15082
15093
|
if (typeof methodValue !== "string") {
|
|
15083
15094
|
throw new Error("Schema method literal must be a string");
|
|
15084
15095
|
}
|
|
@@ -15387,8 +15398,17 @@ var Server = class extends Protocol {
|
|
|
15387
15398
|
var import_node_process = __toESM(require("node:process"), 1);
|
|
15388
15399
|
|
|
15389
15400
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
15401
|
+
var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
|
|
15390
15402
|
var ReadBuffer = class {
|
|
15403
|
+
constructor(options) {
|
|
15404
|
+
this._maxBufferSize = options?.maxBufferSize ?? STDIO_DEFAULT_MAX_BUFFER_SIZE;
|
|
15405
|
+
}
|
|
15391
15406
|
append(chunk) {
|
|
15407
|
+
const newSize = (this._buffer?.length ?? 0) + chunk.length;
|
|
15408
|
+
if (newSize > this._maxBufferSize) {
|
|
15409
|
+
this.clear();
|
|
15410
|
+
throw new Error(`ReadBuffer exceeded maximum size of ${this._maxBufferSize} bytes`);
|
|
15411
|
+
}
|
|
15392
15412
|
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
15393
15413
|
}
|
|
15394
15414
|
readMessage() {
|
|
@@ -15416,18 +15436,24 @@ function serializeMessage(message) {
|
|
|
15416
15436
|
|
|
15417
15437
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
15418
15438
|
var StdioServerTransport = class {
|
|
15419
|
-
constructor(_stdin = import_node_process.default.stdin, _stdout = import_node_process.default.stdout) {
|
|
15439
|
+
constructor(_stdin = import_node_process.default.stdin, _stdout = import_node_process.default.stdout, options) {
|
|
15420
15440
|
this._stdin = _stdin;
|
|
15421
15441
|
this._stdout = _stdout;
|
|
15422
|
-
this._readBuffer = new ReadBuffer();
|
|
15423
15442
|
this._started = false;
|
|
15424
15443
|
this._ondata = (chunk) => {
|
|
15425
|
-
|
|
15426
|
-
|
|
15444
|
+
try {
|
|
15445
|
+
this._readBuffer.append(chunk);
|
|
15446
|
+
this.processReadBuffer();
|
|
15447
|
+
} catch (error2) {
|
|
15448
|
+
this.onerror?.(error2);
|
|
15449
|
+
this.close().catch(() => {
|
|
15450
|
+
});
|
|
15451
|
+
}
|
|
15427
15452
|
};
|
|
15428
15453
|
this._onerror = (error2) => {
|
|
15429
15454
|
this.onerror?.(error2);
|
|
15430
15455
|
};
|
|
15456
|
+
this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize });
|
|
15431
15457
|
}
|
|
15432
15458
|
/**
|
|
15433
15459
|
* Starts listening for messages on stdin.
|
|
@@ -16242,7 +16268,10 @@ var VALID_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
|
|
|
16242
16268
|
"orchestrator-state",
|
|
16243
16269
|
"epic-orchestrator-state",
|
|
16244
16270
|
"epic-planner-state",
|
|
16245
|
-
"epic-kickoff"
|
|
16271
|
+
"epic-kickoff",
|
|
16272
|
+
"parallel-orchestrator-state",
|
|
16273
|
+
"parallel-planner-state",
|
|
16274
|
+
"parallel-kickoff"
|
|
16246
16275
|
]);
|
|
16247
16276
|
function resolveValidateOrchestrationArtifactsToolInput(rawInput, fallbackWorkspaceRoot) {
|
|
16248
16277
|
const args = asToolArgumentObject(rawInput);
|
|
@@ -16987,7 +17016,10 @@ var REPO_AUTOMATION_TOOL_DEFINITIONS = [
|
|
|
16987
17016
|
"orchestrator-state",
|
|
16988
17017
|
"epic-orchestrator-state",
|
|
16989
17018
|
"epic-planner-state",
|
|
16990
|
-
"epic-kickoff"
|
|
17019
|
+
"epic-kickoff",
|
|
17020
|
+
"parallel-orchestrator-state",
|
|
17021
|
+
"parallel-planner-state",
|
|
17022
|
+
"parallel-kickoff"
|
|
16991
17023
|
],
|
|
16992
17024
|
description: "The type of orchestration artifact to validate."
|
|
16993
17025
|
},
|
|
@@ -16997,7 +17029,7 @@ var REPO_AUTOMATION_TOOL_DEFINITIONS = [
|
|
|
16997
17029
|
},
|
|
16998
17030
|
require_complete: {
|
|
16999
17031
|
type: "boolean",
|
|
17000
|
-
description: "When true and artifact_type is 'orchestrator-state' or '
|
|
17032
|
+
description: "When true and artifact_type is 'orchestrator-state', 'epic-orchestrator-state', or 'parallel-orchestrator-state', require all phases to be complete."
|
|
17001
17033
|
},
|
|
17002
17034
|
require_model_routing: {
|
|
17003
17035
|
type: "boolean",
|
|
@@ -17013,7 +17045,7 @@ var REPO_AUTOMATION_TOOL_DEFINITIONS = [
|
|
|
17013
17045
|
},
|
|
17014
17046
|
require_ready_for_execution: {
|
|
17015
17047
|
type: "boolean",
|
|
17016
|
-
description: "When true and artifact_type is 'epic-planner-state', require every child to be prepared and preflight-cleared."
|
|
17048
|
+
description: "When true and artifact_type is 'epic-planner-state' or 'parallel-planner-state', require every child to be prepared and preflight-cleared."
|
|
17017
17049
|
}
|
|
17018
17050
|
},
|
|
17019
17051
|
required: ["workspace_root", "artifact_type", "artifact_path"],
|
|
@@ -23307,7 +23339,10 @@ function validateCodexModelRoutingReceipts(value) {
|
|
|
23307
23339
|
}
|
|
23308
23340
|
function delegatedAgentNames(state) {
|
|
23309
23341
|
const result = /* @__PURE__ */ new Set();
|
|
23310
|
-
|
|
23342
|
+
let receipts = state["delegation_receipts"];
|
|
23343
|
+
if (isObject4(receipts)) {
|
|
23344
|
+
receipts = receipts["agents"];
|
|
23345
|
+
}
|
|
23311
23346
|
if (!Array.isArray(receipts)) {
|
|
23312
23347
|
return result;
|
|
23313
23348
|
}
|
|
@@ -23701,7 +23736,10 @@ function validateCodexTopologyReceipts(value) {
|
|
|
23701
23736
|
}
|
|
23702
23737
|
function delegatedAgentNames2(state) {
|
|
23703
23738
|
const result = /* @__PURE__ */ new Set();
|
|
23704
|
-
|
|
23739
|
+
let receipts = state["delegation_receipts"];
|
|
23740
|
+
if (isObject5(receipts)) {
|
|
23741
|
+
receipts = receipts["agents"];
|
|
23742
|
+
}
|
|
23705
23743
|
if (!Array.isArray(receipts)) {
|
|
23706
23744
|
return result;
|
|
23707
23745
|
}
|
|
@@ -25354,6 +25392,9 @@ function stateList(state, key, expected) {
|
|
|
25354
25392
|
return value;
|
|
25355
25393
|
}
|
|
25356
25394
|
function listReceipts(receipts) {
|
|
25395
|
+
if (isObject8(receipts)) {
|
|
25396
|
+
receipts = receipts["agents"];
|
|
25397
|
+
}
|
|
25357
25398
|
if (!Array.isArray(receipts)) {
|
|
25358
25399
|
return [];
|
|
25359
25400
|
}
|
|
@@ -25764,7 +25805,10 @@ function isObject12(value) {
|
|
|
25764
25805
|
}
|
|
25765
25806
|
function delegatedAgents(state) {
|
|
25766
25807
|
const agents = /* @__PURE__ */ new Set();
|
|
25767
|
-
|
|
25808
|
+
let receipts = state["delegation_receipts"];
|
|
25809
|
+
if (isObject12(receipts)) {
|
|
25810
|
+
receipts = receipts["agents"];
|
|
25811
|
+
}
|
|
25768
25812
|
if (Array.isArray(receipts)) {
|
|
25769
25813
|
for (const receipt of receipts) {
|
|
25770
25814
|
if (!isObject12(receipt)) {
|
|
@@ -25867,6 +25911,7 @@ var STEP_STATUS_KEYS = [
|
|
|
25867
25911
|
"step9_status",
|
|
25868
25912
|
"step10_status"
|
|
25869
25913
|
];
|
|
25914
|
+
var AGENT_RECEIPT_NAMESPACE_KEY = "agents";
|
|
25870
25915
|
var STEP_SPECIFIC_EXTRA_STATUS = /* @__PURE__ */ new Map([
|
|
25871
25916
|
["step6_status", /* @__PURE__ */ new Set(["blocked_remediation_loop_limit"])],
|
|
25872
25917
|
[
|
|
@@ -25915,12 +25960,22 @@ function validateListDelegationReceipts(receipts) {
|
|
|
25915
25960
|
}
|
|
25916
25961
|
function validateNamespacedDelegationReceipts(receipts) {
|
|
25917
25962
|
const errors = [];
|
|
25918
|
-
const unsupportedKeys = Object.keys(receipts).filter(
|
|
25963
|
+
const unsupportedKeys = Object.keys(receipts).filter(
|
|
25964
|
+
(key) => key !== AGENT_RECEIPT_NAMESPACE_KEY && key !== PROMOTION_RECEIPT_NAMESPACE_KEY
|
|
25965
|
+
).sort();
|
|
25919
25966
|
for (const key of unsupportedKeys) {
|
|
25920
25967
|
errors.push(
|
|
25921
25968
|
`Checkpoint delegation_receipts object contains unsupported key: ${key}`
|
|
25922
25969
|
);
|
|
25923
25970
|
}
|
|
25971
|
+
if (AGENT_RECEIPT_NAMESPACE_KEY in receipts) {
|
|
25972
|
+
const agentReceipts = receipts[AGENT_RECEIPT_NAMESPACE_KEY];
|
|
25973
|
+
if (!Array.isArray(agentReceipts)) {
|
|
25974
|
+
errors.push("Checkpoint delegation_receipts.agents must be a list.");
|
|
25975
|
+
} else {
|
|
25976
|
+
errors.push(...validateListDelegationReceipts(agentReceipts));
|
|
25977
|
+
}
|
|
25978
|
+
}
|
|
25924
25979
|
const promotionReceipts = receipts[PROMOTION_RECEIPT_NAMESPACE_KEY];
|
|
25925
25980
|
if (promotionReceipts === void 0 || promotionReceipts === null) {
|
|
25926
25981
|
return errors;
|
|
@@ -26045,203 +26100,1611 @@ function validateOrchestratorStateText(text, options = {}) {
|
|
|
26045
26100
|
return errors;
|
|
26046
26101
|
}
|
|
26047
26102
|
|
|
26048
|
-
// ../../extensions/drm-copilot/src/lib/validate/
|
|
26049
|
-
var
|
|
26050
|
-
var
|
|
26051
|
-
|
|
26052
|
-
|
|
26053
|
-
|
|
26054
|
-
|
|
26055
|
-
|
|
26056
|
-
|
|
26057
|
-
"
|
|
26058
|
-
"
|
|
26059
|
-
"
|
|
26060
|
-
"
|
|
26061
|
-
"
|
|
26062
|
-
"
|
|
26063
|
-
"## Appendix B: Toolchain Commands Reference"
|
|
26064
|
-
];
|
|
26065
|
-
var POLICY_AUDIT_REQUIRED_CHECKLIST_LABELS = [
|
|
26066
|
-
"TypeScript baseline coverage artifact:",
|
|
26067
|
-
"TypeScript post-change coverage artifact:",
|
|
26068
|
-
"PowerShell baseline coverage artifact:",
|
|
26069
|
-
"PowerShell post-change coverage artifact:",
|
|
26070
|
-
"Per-language comparison summary:"
|
|
26071
|
-
];
|
|
26072
|
-
var POLICY_AUDIT_COMPARISON_HEADING = "### 1.2.1 Per-Language Coverage Comparison";
|
|
26073
|
-
var PLACEHOLDER_MARKERS = [
|
|
26074
|
-
"[n]",
|
|
26075
|
-
"[path",
|
|
26076
|
-
"[artifact",
|
|
26077
|
-
"[section reference",
|
|
26078
|
-
"[language]",
|
|
26079
|
-
"tbd",
|
|
26080
|
-
"unverified",
|
|
26081
|
-
"missing"
|
|
26082
|
-
];
|
|
26083
|
-
var TEMPLATE_RESOLVER_TOOL = "resolve_policy_audit_template_asset";
|
|
26084
|
-
var TEMPLATE_RESOLVER_MISSING_MARKERS = [
|
|
26085
|
-
"not exposed",
|
|
26086
|
-
"was not exposed",
|
|
26087
|
-
"missing resolver exposure",
|
|
26088
|
-
"fallback template",
|
|
26089
|
-
"fallback-template"
|
|
26103
|
+
// ../../extensions/drm-copilot/src/lib/validate/parallel-kickoff-artifact.ts
|
|
26104
|
+
var KICKOFF_HEADING_RE2 = /^# Parallel Kickoff: (?<slug>[a-z0-9][a-z0-9-]*)$/;
|
|
26105
|
+
var PARALLEL_RUN_RE = /Run `\/parallel-run (?<slug>[a-z0-9][a-z0-9-]*)`/;
|
|
26106
|
+
var MANIFEST_RE2 = /docs\/features\/parallel\/[a-z0-9][a-z0-9-]*\/parallel\.md/;
|
|
26107
|
+
var PLAN_BRANCH_RE = /parallel\/[a-z0-9][a-z0-9-]*-plan/;
|
|
26108
|
+
var RESUME_RE2 = /(?:Every item|Each item|items)\s+resumes?\s+at atomic execution\s+from\s+(?:its|their)\s+committed plan-path\s+on\s+(?:its|their)\s+own\s+(?:pushed\s+)?feature branch/i;
|
|
26109
|
+
var INTEGRITY_COMMIT_RE2 = /^(?:-\s*)?planning_commit:\s*`?(?<commit>[0-9a-fA-F]{7,64})`?\s*$/;
|
|
26110
|
+
var LINE_SPLIT_RE = /\r\n|\r|\n/u;
|
|
26111
|
+
var ITEM_HEADERS = [
|
|
26112
|
+
"issue_num",
|
|
26113
|
+
"feature_folder",
|
|
26114
|
+
"cohort",
|
|
26115
|
+
"complexity",
|
|
26116
|
+
"branch",
|
|
26117
|
+
"plan-path"
|
|
26090
26118
|
];
|
|
26091
|
-
|
|
26092
|
-
|
|
26093
|
-
|
|
26094
|
-
|
|
26095
|
-
|
|
26096
|
-
|
|
26097
|
-
|
|
26098
|
-
|
|
26099
|
-
|
|
26100
|
-
|
|
26101
|
-
|
|
26102
|
-
const
|
|
26103
|
-
|
|
26104
|
-
|
|
26105
|
-
|
|
26106
|
-
|
|
26107
|
-
|
|
26108
|
-
|
|
26109
|
-
|
|
26110
|
-
|
|
26111
|
-
|
|
26112
|
-
const rows = [];
|
|
26113
|
-
for (const line of text.split("\n")) {
|
|
26114
|
-
if (!line.startsWith("|")) {
|
|
26115
|
-
continue;
|
|
26116
|
-
}
|
|
26117
|
-
const segments = line.split("|");
|
|
26118
|
-
const cells = segments.slice(1, -1).map((cell) => cell.trim());
|
|
26119
|
-
if (cells.length !== 7) {
|
|
26120
|
-
continue;
|
|
26121
|
-
}
|
|
26122
|
-
const language = cells[0] ?? "";
|
|
26123
|
-
if (language === "Language" || language === "----------" || !language) {
|
|
26119
|
+
var HASH_HEADERS2 = /* @__PURE__ */ new Set([
|
|
26120
|
+
"plan-hash",
|
|
26121
|
+
"plan_hash",
|
|
26122
|
+
"git-blob-sha",
|
|
26123
|
+
"git_blob_sha"
|
|
26124
|
+
]);
|
|
26125
|
+
var COMPLEXITY_BANDS2 = /* @__PURE__ */ new Set(["C1", "C2", "C3", "C4"]);
|
|
26126
|
+
function splitSections3(text) {
|
|
26127
|
+
const sections = /* @__PURE__ */ new Map();
|
|
26128
|
+
const errors = [];
|
|
26129
|
+
let current;
|
|
26130
|
+
for (const line of text.split(LINE_SPLIT_RE).slice(1)) {
|
|
26131
|
+
if (line.startsWith("## ")) {
|
|
26132
|
+
current = line.slice(3).trim();
|
|
26133
|
+
if (sections.has(current)) {
|
|
26134
|
+
errors.push(
|
|
26135
|
+
`Parallel kickoff contains duplicate section: ## ${current}`
|
|
26136
|
+
);
|
|
26137
|
+
} else {
|
|
26138
|
+
sections.set(current, []);
|
|
26139
|
+
}
|
|
26124
26140
|
continue;
|
|
26125
26141
|
}
|
|
26126
|
-
if (
|
|
26127
|
-
|
|
26142
|
+
if (current !== void 0) {
|
|
26143
|
+
sections.get(current)?.push(line);
|
|
26128
26144
|
}
|
|
26129
|
-
rows.push({
|
|
26130
|
-
Language: language,
|
|
26131
|
-
"Files Changed": cells[1] ?? "",
|
|
26132
|
-
Tests: cells[2] ?? "",
|
|
26133
|
-
"Test Result": cells[3] ?? "",
|
|
26134
|
-
"Baseline Coverage": cells[4] ?? "",
|
|
26135
|
-
"Post-Change Coverage": cells[5] ?? "",
|
|
26136
|
-
"New Code Coverage": cells[6] ?? ""
|
|
26137
|
-
});
|
|
26138
26145
|
}
|
|
26139
|
-
|
|
26140
|
-
|
|
26141
|
-
|
|
26142
|
-
|
|
26143
|
-
|
|
26144
|
-
if (stripped.startsWith("- ") && stripped.includes(label)) {
|
|
26145
|
-
return stripped;
|
|
26146
|
+
for (const required2 of ["Invocation Prompt", "Item Summary"]) {
|
|
26147
|
+
if (!sections.has(required2)) {
|
|
26148
|
+
errors.push(
|
|
26149
|
+
`Parallel kickoff is missing required section: ## ${required2}`
|
|
26150
|
+
);
|
|
26146
26151
|
}
|
|
26147
26152
|
}
|
|
26148
|
-
return
|
|
26153
|
+
return { sections, errors };
|
|
26149
26154
|
}
|
|
26150
|
-
function
|
|
26151
|
-
|
|
26152
|
-
|
|
26153
|
-
|
|
26154
|
-
const stripped = line.trim();
|
|
26155
|
-
if (stripped === POLICY_AUDIT_COMPARISON_HEADING) {
|
|
26156
|
-
inSection = true;
|
|
26157
|
-
continue;
|
|
26158
|
-
}
|
|
26159
|
-
if (inSection && stripped.startsWith("### ")) {
|
|
26160
|
-
break;
|
|
26161
|
-
}
|
|
26162
|
-
if (!inSection || !stripped.startsWith("- ")) {
|
|
26163
|
-
continue;
|
|
26164
|
-
}
|
|
26165
|
-
const body = stripped.slice(2);
|
|
26166
|
-
const colonIndex = body.indexOf(":");
|
|
26167
|
-
if (colonIndex === -1) {
|
|
26168
|
-
continue;
|
|
26169
|
-
}
|
|
26170
|
-
const language = body.slice(0, colonIndex);
|
|
26171
|
-
comparisonLines.set(language.trim().toLowerCase(), stripped);
|
|
26155
|
+
function parseCells2(line) {
|
|
26156
|
+
const stripped = line.trim();
|
|
26157
|
+
if (!stripped.startsWith("|") || !stripped.endsWith("|")) {
|
|
26158
|
+
return void 0;
|
|
26172
26159
|
}
|
|
26173
|
-
return
|
|
26174
|
-
}
|
|
26175
|
-
function escapeRegExp3(value) {
|
|
26176
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26160
|
+
return stripped.slice(1, -1).split("|").map((cell) => cell.trim().replace(/^`|`$/g, ""));
|
|
26177
26161
|
}
|
|
26178
|
-
function
|
|
26179
|
-
|
|
26180
|
-
return pattern.test(line);
|
|
26162
|
+
function isSeparator2(cells) {
|
|
26163
|
+
return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/.test(cell));
|
|
26181
26164
|
}
|
|
26182
|
-
function
|
|
26165
|
+
function tableRows2(lines, expectedHeaders) {
|
|
26166
|
+
const nonempty = lines.filter((line) => line.trim().length > 0);
|
|
26167
|
+
if (nonempty.length < 2) {
|
|
26168
|
+
return {
|
|
26169
|
+
rows: [],
|
|
26170
|
+
errors: [
|
|
26171
|
+
"Parallel kickoff table is missing its header or separator row."
|
|
26172
|
+
]
|
|
26173
|
+
};
|
|
26174
|
+
}
|
|
26175
|
+
const headers = parseCells2(nonempty[0] ?? "");
|
|
26176
|
+
const separator = parseCells2(nonempty[1] ?? "");
|
|
26183
26177
|
const errors = [];
|
|
26184
|
-
|
|
26185
|
-
|
|
26186
|
-
|
|
26187
|
-
|
|
26188
|
-
continue;
|
|
26189
|
-
}
|
|
26190
|
-
if (hasPlaceholderMarker(line)) {
|
|
26191
|
-
errors.push(
|
|
26192
|
-
`Policy audit checklist line still contains placeholder text: ${label}`
|
|
26193
|
-
);
|
|
26194
|
-
}
|
|
26178
|
+
if (headers === void 0 || headers.length !== expectedHeaders.length || headers.some((value, index) => value !== expectedHeaders[index])) {
|
|
26179
|
+
errors.push(
|
|
26180
|
+
`Parallel kickoff item table headers must be: ${expectedHeaders.join(" | ")}`
|
|
26181
|
+
);
|
|
26195
26182
|
}
|
|
26196
|
-
|
|
26197
|
-
|
|
26198
|
-
errors.push("Policy audit missing coverage metrics table rows.");
|
|
26183
|
+
if (separator === void 0 || separator.length !== expectedHeaders.length || !isSeparator2(separator)) {
|
|
26184
|
+
errors.push("Parallel kickoff table separator row is invalid.");
|
|
26199
26185
|
}
|
|
26200
|
-
|
|
26186
|
+
const rows = [];
|
|
26187
|
+
for (const line of nonempty.slice(2)) {
|
|
26188
|
+
const cells = parseCells2(line);
|
|
26189
|
+
if (cells === void 0 || cells.length !== expectedHeaders.length) {
|
|
26190
|
+
errors.push(`Parallel kickoff table row is invalid: ${line}`);
|
|
26191
|
+
} else {
|
|
26192
|
+
rows.push(cells);
|
|
26193
|
+
}
|
|
26194
|
+
}
|
|
26195
|
+
if (rows.length === 0) {
|
|
26201
26196
|
errors.push(
|
|
26202
|
-
|
|
26197
|
+
"Parallel kickoff item table must contain at least one item row."
|
|
26203
26198
|
);
|
|
26204
26199
|
}
|
|
26205
|
-
|
|
26206
|
-
|
|
26207
|
-
|
|
26208
|
-
|
|
26209
|
-
|
|
26210
|
-
|
|
26211
|
-
const
|
|
26212
|
-
|
|
26213
|
-
|
|
26214
|
-
|
|
26215
|
-
errors.push(
|
|
26216
|
-
`Policy audit missing numeric baseline coverage for ${language}.`
|
|
26217
|
-
);
|
|
26218
|
-
}
|
|
26219
|
-
if (!isNaValue(postChange) && !hasNumericCoverage(postChange)) {
|
|
26220
|
-
errors.push(
|
|
26221
|
-
`Policy audit missing numeric post-change coverage for ${language}.`
|
|
26222
|
-
);
|
|
26223
|
-
}
|
|
26224
|
-
if (!isNaValue(newCode) && !hasNumericCoverage(newCode)) {
|
|
26225
|
-
errors.push(
|
|
26226
|
-
`Policy audit missing numeric new/changed-code coverage for ${language}.`
|
|
26200
|
+
return { rows, errors };
|
|
26201
|
+
}
|
|
26202
|
+
function parseItems(lines) {
|
|
26203
|
+
const table = tableRows2(lines, ITEM_HEADERS);
|
|
26204
|
+
const items = [];
|
|
26205
|
+
table.rows.forEach((row, index) => {
|
|
26206
|
+
const issueNum = Number(row[0]);
|
|
26207
|
+
if (!Number.isInteger(issueNum)) {
|
|
26208
|
+
table.errors.push(
|
|
26209
|
+
`Parallel kickoff item row ${String(index)} issue_num must be an integer.`
|
|
26227
26210
|
);
|
|
26211
|
+
return;
|
|
26228
26212
|
}
|
|
26229
|
-
|
|
26230
|
-
|
|
26231
|
-
|
|
26232
|
-
|
|
26233
|
-
if (comparisonLine === void 0) {
|
|
26234
|
-
errors.push(
|
|
26235
|
-
`Policy audit missing per-language comparison line for ${language}.`
|
|
26213
|
+
const cohort = Number(row[2]);
|
|
26214
|
+
if (!Number.isInteger(cohort)) {
|
|
26215
|
+
table.errors.push(
|
|
26216
|
+
`Parallel kickoff item row ${String(index)} cohort must be an integer.`
|
|
26236
26217
|
);
|
|
26237
|
-
|
|
26218
|
+
return;
|
|
26238
26219
|
}
|
|
26239
|
-
|
|
26240
|
-
|
|
26241
|
-
|
|
26220
|
+
const complexity = row[3] ?? "";
|
|
26221
|
+
if (!COMPLEXITY_BANDS2.has(complexity)) {
|
|
26222
|
+
table.errors.push(
|
|
26223
|
+
`Parallel kickoff item row ${String(index)} complexity must be C1-C4.`
|
|
26242
26224
|
);
|
|
26243
26225
|
}
|
|
26244
|
-
|
|
26226
|
+
items.push({
|
|
26227
|
+
issueNum,
|
|
26228
|
+
featureFolder: row[1] ?? "",
|
|
26229
|
+
cohort,
|
|
26230
|
+
complexity,
|
|
26231
|
+
branch: row[4] ?? "",
|
|
26232
|
+
planPath: row[5] ?? ""
|
|
26233
|
+
});
|
|
26234
|
+
});
|
|
26235
|
+
return { items, errors: table.errors };
|
|
26236
|
+
}
|
|
26237
|
+
function parseIntegrityTable(tableLines) {
|
|
26238
|
+
const planHashes = {};
|
|
26239
|
+
const errors = [];
|
|
26240
|
+
const header = parseCells2(tableLines[0] ?? "");
|
|
26241
|
+
if (header === void 0 || header.length !== 2 || header[0] !== "plan-path" || !HASH_HEADERS2.has(header[1] ?? "")) {
|
|
26242
|
+
errors.push(
|
|
26243
|
+
"Parallel kickoff integrity table headers must be plan-path and plan-hash."
|
|
26244
|
+
);
|
|
26245
|
+
} else if (tableLines.length < 2) {
|
|
26246
|
+
errors.push(
|
|
26247
|
+
"Parallel kickoff integrity table is missing its separator row."
|
|
26248
|
+
);
|
|
26249
|
+
} else {
|
|
26250
|
+
const separator = parseCells2(tableLines[1] ?? "");
|
|
26251
|
+
if (separator === void 0 || separator.length !== 2 || !isSeparator2(separator)) {
|
|
26252
|
+
errors.push("Parallel kickoff integrity table separator row is invalid.");
|
|
26253
|
+
}
|
|
26254
|
+
for (const line of tableLines.slice(2)) {
|
|
26255
|
+
const cells = parseCells2(line);
|
|
26256
|
+
if (cells === void 0 || cells.length !== 2 || !/^[0-9a-fA-F]{40,64}$/.test(cells[1] ?? "")) {
|
|
26257
|
+
errors.push(`Parallel kickoff integrity table row is invalid: ${line}`);
|
|
26258
|
+
continue;
|
|
26259
|
+
}
|
|
26260
|
+
const planPath = cells[0] ?? "";
|
|
26261
|
+
if (planHashes[planPath] !== void 0) {
|
|
26262
|
+
errors.push(
|
|
26263
|
+
`Parallel kickoff integrity repeats plan path: '${planPath}'.`
|
|
26264
|
+
);
|
|
26265
|
+
}
|
|
26266
|
+
planHashes[planPath] = (cells[1] ?? "").toLowerCase();
|
|
26267
|
+
}
|
|
26268
|
+
}
|
|
26269
|
+
return { planHashes, errors };
|
|
26270
|
+
}
|
|
26271
|
+
function parseIntegrity2(lines) {
|
|
26272
|
+
let planningCommit;
|
|
26273
|
+
const errors = [];
|
|
26274
|
+
const tableLines = [];
|
|
26275
|
+
for (const line of lines) {
|
|
26276
|
+
if (line.trim().length === 0) {
|
|
26277
|
+
continue;
|
|
26278
|
+
}
|
|
26279
|
+
const match = INTEGRITY_COMMIT_RE2.exec(line.trim());
|
|
26280
|
+
if (match?.groups?.["commit"] !== void 0) {
|
|
26281
|
+
if (planningCommit !== void 0) {
|
|
26282
|
+
errors.push(
|
|
26283
|
+
"Parallel kickoff integrity has duplicate planning_commit fields."
|
|
26284
|
+
);
|
|
26285
|
+
}
|
|
26286
|
+
planningCommit = match.groups["commit"].toLowerCase();
|
|
26287
|
+
} else if (line.trim().startsWith("|")) {
|
|
26288
|
+
tableLines.push(line);
|
|
26289
|
+
} else {
|
|
26290
|
+
errors.push(`Parallel kickoff integrity line is invalid: ${line}`);
|
|
26291
|
+
}
|
|
26292
|
+
}
|
|
26293
|
+
let planHashes = {};
|
|
26294
|
+
if (tableLines.length > 0) {
|
|
26295
|
+
const table = parseIntegrityTable(tableLines);
|
|
26296
|
+
planHashes = table.planHashes;
|
|
26297
|
+
errors.push(...table.errors);
|
|
26298
|
+
}
|
|
26299
|
+
return {
|
|
26300
|
+
...planningCommit === void 0 ? {} : { planningCommit },
|
|
26301
|
+
planHashes,
|
|
26302
|
+
errors
|
|
26303
|
+
};
|
|
26304
|
+
}
|
|
26305
|
+
function parseParallelKickoff(text) {
|
|
26306
|
+
const lines = text.split(LINE_SPLIT_RE);
|
|
26307
|
+
if (text.length === 0) {
|
|
26308
|
+
return { errors: ["Parallel kickoff is empty."] };
|
|
26309
|
+
}
|
|
26310
|
+
const heading = KICKOFF_HEADING_RE2.exec(lines[0] ?? "");
|
|
26311
|
+
if (heading?.groups?.["slug"] === void 0) {
|
|
26312
|
+
return {
|
|
26313
|
+
errors: [
|
|
26314
|
+
"Parallel kickoff first line must match '# Parallel Kickoff: <slug>'."
|
|
26315
|
+
]
|
|
26316
|
+
};
|
|
26317
|
+
}
|
|
26318
|
+
const sectionResult = splitSections3(text);
|
|
26319
|
+
const invocation = (sectionResult.sections.get("Invocation Prompt") ?? []).join("\n");
|
|
26320
|
+
const invocationSlug = PARALLEL_RUN_RE.exec(invocation)?.groups?.["slug"];
|
|
26321
|
+
const manifestMatch = MANIFEST_RE2.exec(invocation);
|
|
26322
|
+
const branchMatch = PLAN_BRANCH_RE.exec(invocation);
|
|
26323
|
+
const resumeMatch = RESUME_RE2.exec(invocation);
|
|
26324
|
+
if (invocationSlug === void 0) {
|
|
26325
|
+
sectionResult.errors.push(
|
|
26326
|
+
"Parallel kickoff invocation must contain `Run /parallel-run <slug>`."
|
|
26327
|
+
);
|
|
26328
|
+
}
|
|
26329
|
+
if (manifestMatch?.[0] === void 0 || branchMatch?.[0] === void 0 || resumeMatch === null) {
|
|
26330
|
+
sectionResult.errors.push(
|
|
26331
|
+
"Parallel kickoff invocation must structurally name the manifest, plan-home branch, and atomic-execution resume boundary."
|
|
26332
|
+
);
|
|
26333
|
+
}
|
|
26334
|
+
const itemResult = parseItems(
|
|
26335
|
+
sectionResult.sections.get("Item Summary") ?? []
|
|
26336
|
+
);
|
|
26337
|
+
sectionResult.errors.push(...itemResult.errors);
|
|
26338
|
+
const integrity = parseIntegrity2(
|
|
26339
|
+
sectionResult.sections.get("Integrity") ?? []
|
|
26340
|
+
);
|
|
26341
|
+
sectionResult.errors.push(...integrity.errors);
|
|
26342
|
+
if (sectionResult.errors.length > 0 || invocationSlug === void 0 || manifestMatch?.[0] === void 0 || branchMatch?.[0] === void 0 || resumeMatch === null) {
|
|
26343
|
+
return { errors: sectionResult.errors };
|
|
26344
|
+
}
|
|
26345
|
+
return {
|
|
26346
|
+
parsed: {
|
|
26347
|
+
slug: heading.groups["slug"],
|
|
26348
|
+
invocationSlug,
|
|
26349
|
+
manifestPath: manifestMatch[0],
|
|
26350
|
+
planHomeBranch: branchMatch[0],
|
|
26351
|
+
items: itemResult.items,
|
|
26352
|
+
...integrity.planningCommit === void 0 ? {} : { planningCommit: integrity.planningCommit },
|
|
26353
|
+
planHashes: integrity.planHashes
|
|
26354
|
+
},
|
|
26355
|
+
errors: []
|
|
26356
|
+
};
|
|
26357
|
+
}
|
|
26358
|
+
function validateParallelKickoffText(text) {
|
|
26359
|
+
return parseParallelKickoff(text).errors;
|
|
26360
|
+
}
|
|
26361
|
+
|
|
26362
|
+
// ../../extensions/drm-copilot/src/lib/validate/parallel-state-shared.ts
|
|
26363
|
+
function words(text) {
|
|
26364
|
+
return text.split(" ");
|
|
26365
|
+
}
|
|
26366
|
+
var VALID_ITEM_STATES = words(
|
|
26367
|
+
"proposed admitted prepared scheduled in_flight merged withdrawn blocked"
|
|
26368
|
+
);
|
|
26369
|
+
var VALID_MERGE_STATUS2 = words(
|
|
26370
|
+
"not_started worktree_created pr_open ci_green merged worktree_removed blocked_drift blocked_ci_loop_limit"
|
|
26371
|
+
);
|
|
26372
|
+
var VALID_SOURCES = words("derived declared observed");
|
|
26373
|
+
var VALID_KINDS = words("feature bug");
|
|
26374
|
+
var VALID_MODES = words("closed open");
|
|
26375
|
+
var VALID_MUTATION_OPS = words("add remove close requeue");
|
|
26376
|
+
var VALID_DISPOSITIONS = words("detach abandon");
|
|
26377
|
+
var VALID_EDGE_REASONS = words(
|
|
26378
|
+
"path_overlap module_overlap shared_surface_overlap contract_dependency"
|
|
26379
|
+
);
|
|
26380
|
+
var VALID_DRIFT_ACTIONS = words(
|
|
26381
|
+
"raised_blocking_finding halted_later_started_item"
|
|
26382
|
+
);
|
|
26383
|
+
var MERGED_MERGE_STATUSES = words("merged worktree_removed");
|
|
26384
|
+
var BLOCKED_MERGE_STATUSES = words(
|
|
26385
|
+
"blocked_drift blocked_ci_loop_limit"
|
|
26386
|
+
);
|
|
26387
|
+
var BLAST_RADIUS_LIST_FIELDS = words(
|
|
26388
|
+
"paths modules shared_surfaces contracts"
|
|
26389
|
+
);
|
|
26390
|
+
var PROHIBITED_ANY_LEVEL_KEYS = words(
|
|
26391
|
+
"depends_on integration_branch epic_merge_pr"
|
|
26392
|
+
);
|
|
26393
|
+
var ROOT_PATH = "<root>";
|
|
26394
|
+
function isObject14(value) {
|
|
26395
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26396
|
+
}
|
|
26397
|
+
function pythonRepr9(value) {
|
|
26398
|
+
if (value === null || value === void 0) {
|
|
26399
|
+
return "None";
|
|
26400
|
+
}
|
|
26401
|
+
if (typeof value === "boolean") {
|
|
26402
|
+
return value ? "True" : "False";
|
|
26403
|
+
}
|
|
26404
|
+
if (typeof value === "string") {
|
|
26405
|
+
return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
26406
|
+
}
|
|
26407
|
+
if (Array.isArray(value)) {
|
|
26408
|
+
return `[${value.map(pythonRepr9).join(", ")}]`;
|
|
26409
|
+
}
|
|
26410
|
+
if (isObject14(value)) {
|
|
26411
|
+
const pairs = Object.entries(value).map(
|
|
26412
|
+
([key, item]) => `${pythonRepr9(key)}: ${pythonRepr9(item)}`
|
|
26413
|
+
);
|
|
26414
|
+
return `{${pairs.join(", ")}}`;
|
|
26415
|
+
}
|
|
26416
|
+
return String(value);
|
|
26417
|
+
}
|
|
26418
|
+
function pythonStr2(value) {
|
|
26419
|
+
return typeof value === "string" ? value : pythonRepr9(value);
|
|
26420
|
+
}
|
|
26421
|
+
function isEnumMember(members, value) {
|
|
26422
|
+
return typeof value === "string" && members.includes(value);
|
|
26423
|
+
}
|
|
26424
|
+
function isNonEmptyString2(value) {
|
|
26425
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
26426
|
+
}
|
|
26427
|
+
function isIntegral(value) {
|
|
26428
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
26429
|
+
}
|
|
26430
|
+
function isPositiveInteger(value) {
|
|
26431
|
+
return isIntegral(value) && value > 0;
|
|
26432
|
+
}
|
|
26433
|
+
function isNonNegativeInteger(value) {
|
|
26434
|
+
return isIntegral(value) && value >= 0;
|
|
26435
|
+
}
|
|
26436
|
+
function isStringList(value) {
|
|
26437
|
+
return Array.isArray(value) && value.every(isNonEmptyString2);
|
|
26438
|
+
}
|
|
26439
|
+
function inBoundedRange(value, minimum, maximum) {
|
|
26440
|
+
return isIntegral(value) && value >= minimum && value <= maximum;
|
|
26441
|
+
}
|
|
26442
|
+
function enumError(context, field, members, value) {
|
|
26443
|
+
return `${context} ${field} must be one of ${members.join(", ")}; found: ${pythonRepr9(value)}.`;
|
|
26444
|
+
}
|
|
26445
|
+
function itemContext(context, index) {
|
|
26446
|
+
return `${context} items[${index}]`;
|
|
26447
|
+
}
|
|
26448
|
+
function validateBlastRadiusBlock(radius, context) {
|
|
26449
|
+
if (!isObject14(radius)) {
|
|
26450
|
+
return [`${context} blast_radius must be an object.`];
|
|
26451
|
+
}
|
|
26452
|
+
const errors = [];
|
|
26453
|
+
for (const field of BLAST_RADIUS_LIST_FIELDS) {
|
|
26454
|
+
if (!isStringList(radius[field])) {
|
|
26455
|
+
errors.push(
|
|
26456
|
+
`${context} blast_radius.${field} must be a list of non-empty strings.`
|
|
26457
|
+
);
|
|
26458
|
+
}
|
|
26459
|
+
}
|
|
26460
|
+
const source = radius["source"];
|
|
26461
|
+
if (!isEnumMember(VALID_SOURCES, source)) {
|
|
26462
|
+
errors.push(
|
|
26463
|
+
enumError(context, "blast_radius.source", VALID_SOURCES, source)
|
|
26464
|
+
);
|
|
26465
|
+
}
|
|
26466
|
+
if (!isNonEmptyString2(radius["computed_at"])) {
|
|
26467
|
+
errors.push(
|
|
26468
|
+
`${context} blast_radius.computed_at must be a non-empty string.`
|
|
26469
|
+
);
|
|
26470
|
+
}
|
|
26471
|
+
return errors;
|
|
26472
|
+
}
|
|
26473
|
+
function validateMergeStatus(record2, context, state) {
|
|
26474
|
+
if (!("merge_status" in record2)) {
|
|
26475
|
+
return [];
|
|
26476
|
+
}
|
|
26477
|
+
const mergeStatus = record2["merge_status"];
|
|
26478
|
+
if (!isEnumMember(VALID_MERGE_STATUS2, mergeStatus)) {
|
|
26479
|
+
return [
|
|
26480
|
+
enumError(context, "merge_status", VALID_MERGE_STATUS2, mergeStatus)
|
|
26481
|
+
];
|
|
26482
|
+
}
|
|
26483
|
+
if (isEnumMember(MERGED_MERGE_STATUSES, mergeStatus) && state !== "merged") {
|
|
26484
|
+
return [
|
|
26485
|
+
`${context} merge_status ${pythonRepr9(mergeStatus)} requires state 'merged'; found: ${pythonRepr9(state)}.`
|
|
26486
|
+
];
|
|
26487
|
+
}
|
|
26488
|
+
if (isEnumMember(BLOCKED_MERGE_STATUSES, mergeStatus) && state !== "blocked") {
|
|
26489
|
+
return [
|
|
26490
|
+
`${context} merge_status ${pythonRepr9(mergeStatus)} requires state 'blocked'; found: ${pythonRepr9(state)}.`
|
|
26491
|
+
];
|
|
26492
|
+
}
|
|
26493
|
+
return [];
|
|
26494
|
+
}
|
|
26495
|
+
function validateItemRecord(item, context, requireKind = false) {
|
|
26496
|
+
if (!isObject14(item)) {
|
|
26497
|
+
return [`${context} must be an object.`];
|
|
26498
|
+
}
|
|
26499
|
+
const errors = [];
|
|
26500
|
+
const issueNum = item["issue_num"];
|
|
26501
|
+
if (!isPositiveInteger(issueNum)) {
|
|
26502
|
+
errors.push(
|
|
26503
|
+
`${context} issue_num must be a positive integer; found: ${pythonRepr9(issueNum)}.`
|
|
26504
|
+
);
|
|
26505
|
+
}
|
|
26506
|
+
if (!isNonEmptyString2(item["feature_folder"])) {
|
|
26507
|
+
errors.push(`${context} feature_folder must be a non-empty string.`);
|
|
26508
|
+
}
|
|
26509
|
+
const state = item["state"];
|
|
26510
|
+
if (!isEnumMember(VALID_ITEM_STATES, state)) {
|
|
26511
|
+
errors.push(enumError(context, "state", VALID_ITEM_STATES, state));
|
|
26512
|
+
}
|
|
26513
|
+
if (requireKind) {
|
|
26514
|
+
const kind = item["kind"];
|
|
26515
|
+
if (!isEnumMember(VALID_KINDS, kind)) {
|
|
26516
|
+
errors.push(enumError(context, "kind", VALID_KINDS, kind));
|
|
26517
|
+
}
|
|
26518
|
+
}
|
|
26519
|
+
errors.push(...validateMergeStatus(item, context, state));
|
|
26520
|
+
errors.push(...validateBlastRadiusBlock(item["blast_radius"], context));
|
|
26521
|
+
return errors;
|
|
26522
|
+
}
|
|
26523
|
+
function validateItems(items, context, requireKind = false) {
|
|
26524
|
+
if (!Array.isArray(items)) {
|
|
26525
|
+
return [`${context} items must be a list.`];
|
|
26526
|
+
}
|
|
26527
|
+
const errors = [];
|
|
26528
|
+
const seen = /* @__PURE__ */ new Set();
|
|
26529
|
+
const duplicates = /* @__PURE__ */ new Set();
|
|
26530
|
+
items.forEach((entry, index) => {
|
|
26531
|
+
errors.push(
|
|
26532
|
+
...validateItemRecord(entry, itemContext(context, index), requireKind)
|
|
26533
|
+
);
|
|
26534
|
+
if (!isObject14(entry)) {
|
|
26535
|
+
return;
|
|
26536
|
+
}
|
|
26537
|
+
const issueNum = entry["issue_num"];
|
|
26538
|
+
if (typeof issueNum !== "number" || !Number.isInteger(issueNum)) {
|
|
26539
|
+
return;
|
|
26540
|
+
}
|
|
26541
|
+
if (seen.has(issueNum)) {
|
|
26542
|
+
duplicates.add(issueNum);
|
|
26543
|
+
}
|
|
26544
|
+
seen.add(issueNum);
|
|
26545
|
+
});
|
|
26546
|
+
for (const issueNum of [...duplicates].sort((left, right) => left - right)) {
|
|
26547
|
+
errors.push(`${context} has duplicate items[].issue_num: ${issueNum}.`);
|
|
26548
|
+
}
|
|
26549
|
+
return errors;
|
|
26550
|
+
}
|
|
26551
|
+
function prohibitedKeyErrors(value, path11, context, keys) {
|
|
26552
|
+
const errors = [];
|
|
26553
|
+
if (isObject14(value)) {
|
|
26554
|
+
for (const [key, child] of Object.entries(value)) {
|
|
26555
|
+
if (keys.includes(key)) {
|
|
26556
|
+
errors.push(`${context} carries prohibited key '${key}' at ${path11}.`);
|
|
26557
|
+
}
|
|
26558
|
+
const childPath = path11 === ROOT_PATH ? key : `${path11}.${key}`;
|
|
26559
|
+
errors.push(...prohibitedKeyErrors(child, childPath, context, keys));
|
|
26560
|
+
}
|
|
26561
|
+
} else if (Array.isArray(value)) {
|
|
26562
|
+
value.forEach((entry, index) => {
|
|
26563
|
+
errors.push(
|
|
26564
|
+
...prohibitedKeyErrors(entry, `${path11}[${index}]`, context, keys)
|
|
26565
|
+
);
|
|
26566
|
+
});
|
|
26567
|
+
}
|
|
26568
|
+
return errors;
|
|
26569
|
+
}
|
|
26570
|
+
function scanProhibitedKeys(root, context, deepKeys = PROHIBITED_ANY_LEVEL_KEYS, topLevelKeys = []) {
|
|
26571
|
+
const errors = prohibitedKeyErrors(root, ROOT_PATH, context, deepKeys);
|
|
26572
|
+
if (isObject14(root) && topLevelKeys.length > 0) {
|
|
26573
|
+
for (const key of topLevelKeys) {
|
|
26574
|
+
if (key in root) {
|
|
26575
|
+
errors.push(
|
|
26576
|
+
`${context} carries prohibited key '${key}' at ${ROOT_PATH}.`
|
|
26577
|
+
);
|
|
26578
|
+
}
|
|
26579
|
+
}
|
|
26580
|
+
}
|
|
26581
|
+
return errors;
|
|
26582
|
+
}
|
|
26583
|
+
|
|
26584
|
+
// ../../extensions/drm-copilot/src/lib/validate/parallel-orchestrator-state-cohort-barrier.ts
|
|
26585
|
+
var VIOLATION_PREFIX = "PARALLEL_COHORT_BARRIER_VIOLATION";
|
|
26586
|
+
var ITEM_START_TIMESTAMP_FIELD = "worktree_created_at";
|
|
26587
|
+
var MERGE_CONFIRMATION_TIMESTAMP_FIELD = "merged_at";
|
|
26588
|
+
var NOT_STARTED_MERGE_STATUS = "not_started";
|
|
26589
|
+
var GATING_KEYS = ["conflict_edges", "cohorts"];
|
|
26590
|
+
var FOLDER_HINT_PREFIXES = [
|
|
26591
|
+
"docs/features/active/",
|
|
26592
|
+
"docs/features/completed/",
|
|
26593
|
+
"active/",
|
|
26594
|
+
"completed/"
|
|
26595
|
+
];
|
|
26596
|
+
function normalizeFolderHint2(value) {
|
|
26597
|
+
for (const prefix of FOLDER_HINT_PREFIXES) {
|
|
26598
|
+
if (value.startsWith(prefix)) {
|
|
26599
|
+
return value.slice(prefix.length);
|
|
26600
|
+
}
|
|
26601
|
+
}
|
|
26602
|
+
return value;
|
|
26603
|
+
}
|
|
26604
|
+
function buildReferenceIndex(items) {
|
|
26605
|
+
const records = /* @__PURE__ */ new Map();
|
|
26606
|
+
const byFolderHint = /* @__PURE__ */ new Map();
|
|
26607
|
+
if (!Array.isArray(items)) {
|
|
26608
|
+
return { records, byFolderHint };
|
|
26609
|
+
}
|
|
26610
|
+
for (const entry of items) {
|
|
26611
|
+
if (!isObject14(entry)) {
|
|
26612
|
+
continue;
|
|
26613
|
+
}
|
|
26614
|
+
const issueNum = entry["issue_num"];
|
|
26615
|
+
if (typeof issueNum !== "number" || !isPositiveInteger(issueNum)) {
|
|
26616
|
+
continue;
|
|
26617
|
+
}
|
|
26618
|
+
if (!records.has(issueNum)) {
|
|
26619
|
+
records.set(issueNum, entry);
|
|
26620
|
+
}
|
|
26621
|
+
const folder = entry["feature_folder"];
|
|
26622
|
+
if (typeof folder === "string" && folder.trim().length > 0) {
|
|
26623
|
+
const hint = normalizeFolderHint2(folder);
|
|
26624
|
+
if (!byFolderHint.has(hint)) {
|
|
26625
|
+
byFolderHint.set(hint, issueNum);
|
|
26626
|
+
}
|
|
26627
|
+
}
|
|
26628
|
+
}
|
|
26629
|
+
return { records, byFolderHint };
|
|
26630
|
+
}
|
|
26631
|
+
function resolveReference(reference, references) {
|
|
26632
|
+
if (typeof reference === "string") {
|
|
26633
|
+
return references.byFolderHint.get(normalizeFolderHint2(reference)) ?? null;
|
|
26634
|
+
}
|
|
26635
|
+
if (typeof reference === "number" && isPositiveInteger(reference) && references.records.has(reference)) {
|
|
26636
|
+
return reference;
|
|
26637
|
+
}
|
|
26638
|
+
return null;
|
|
26639
|
+
}
|
|
26640
|
+
function cohortIndexByItem(cohorts, recolorGeneration, references) {
|
|
26641
|
+
const assignments = /* @__PURE__ */ new Map();
|
|
26642
|
+
if (!Array.isArray(cohorts) || !isNonNegativeInteger(recolorGeneration)) {
|
|
26643
|
+
return assignments;
|
|
26644
|
+
}
|
|
26645
|
+
for (const entry of cohorts) {
|
|
26646
|
+
if (!isObject14(entry) || entry["generation"] !== recolorGeneration) {
|
|
26647
|
+
continue;
|
|
26648
|
+
}
|
|
26649
|
+
const cohortIndex = entry["index"];
|
|
26650
|
+
const itemKeys = entry["item_keys"];
|
|
26651
|
+
if (typeof cohortIndex !== "number" || !isNonNegativeInteger(cohortIndex) || !Array.isArray(itemKeys)) {
|
|
26652
|
+
continue;
|
|
26653
|
+
}
|
|
26654
|
+
for (const reference of itemKeys) {
|
|
26655
|
+
const key = resolveReference(reference, references);
|
|
26656
|
+
if (key !== null && !assignments.has(key)) {
|
|
26657
|
+
assignments.set(key, cohortIndex);
|
|
26658
|
+
}
|
|
26659
|
+
}
|
|
26660
|
+
}
|
|
26661
|
+
return assignments;
|
|
26662
|
+
}
|
|
26663
|
+
function hasStarted(record2) {
|
|
26664
|
+
const start = record2[ITEM_START_TIMESTAMP_FIELD];
|
|
26665
|
+
if (typeof start === "string" && start.trim().length > 0) {
|
|
26666
|
+
return true;
|
|
26667
|
+
}
|
|
26668
|
+
const mergeStatus = record2["merge_status"];
|
|
26669
|
+
return typeof mergeStatus === "string" && mergeStatus !== NOT_STARTED_MERGE_STATUS;
|
|
26670
|
+
}
|
|
26671
|
+
function satisfiesBarrier(record2) {
|
|
26672
|
+
return isEnumMember(MERGED_MERGE_STATUSES, record2["merge_status"]);
|
|
26673
|
+
}
|
|
26674
|
+
function mergeConfirmedAfterStart(earlier, later) {
|
|
26675
|
+
const confirmed = earlier[MERGE_CONFIRMATION_TIMESTAMP_FIELD];
|
|
26676
|
+
const started = later[ITEM_START_TIMESTAMP_FIELD];
|
|
26677
|
+
if (typeof confirmed !== "string" || typeof started !== "string") {
|
|
26678
|
+
return false;
|
|
26679
|
+
}
|
|
26680
|
+
return confirmed > started;
|
|
26681
|
+
}
|
|
26682
|
+
function violationEndpoints(first, second, assignments, records) {
|
|
26683
|
+
const firstIndex = assignments.get(first);
|
|
26684
|
+
const secondIndex = assignments.get(second);
|
|
26685
|
+
if (firstIndex !== void 0 && firstIndex === secondIndex) {
|
|
26686
|
+
return [first, second];
|
|
26687
|
+
}
|
|
26688
|
+
if (firstIndex === void 0 || secondIndex === void 0) {
|
|
26689
|
+
return null;
|
|
26690
|
+
}
|
|
26691
|
+
const [earlierKey, laterKey] = firstIndex < secondIndex ? [first, second] : [second, first];
|
|
26692
|
+
const earlier = records.get(earlierKey);
|
|
26693
|
+
const later = records.get(laterKey);
|
|
26694
|
+
if (earlier === void 0 || later === void 0) {
|
|
26695
|
+
return null;
|
|
26696
|
+
}
|
|
26697
|
+
const statusViolation = hasStarted(later) && !satisfiesBarrier(earlier);
|
|
26698
|
+
if (statusViolation || mergeConfirmedAfterStart(earlier, later)) {
|
|
26699
|
+
return [earlierKey, laterKey];
|
|
26700
|
+
}
|
|
26701
|
+
return null;
|
|
26702
|
+
}
|
|
26703
|
+
function validateCohortBarrierOrdering(state) {
|
|
26704
|
+
if (GATING_KEYS.some((key) => !(key in state))) {
|
|
26705
|
+
return [];
|
|
26706
|
+
}
|
|
26707
|
+
const edges = state["conflict_edges"];
|
|
26708
|
+
if (!Array.isArray(edges)) {
|
|
26709
|
+
return [];
|
|
26710
|
+
}
|
|
26711
|
+
const references = buildReferenceIndex(state["items"]);
|
|
26712
|
+
const assignments = cohortIndexByItem(
|
|
26713
|
+
state["cohorts"],
|
|
26714
|
+
state["recolor_generation"],
|
|
26715
|
+
references
|
|
26716
|
+
);
|
|
26717
|
+
const errors = [];
|
|
26718
|
+
for (const entry of edges) {
|
|
26719
|
+
if (!isObject14(entry)) {
|
|
26720
|
+
continue;
|
|
26721
|
+
}
|
|
26722
|
+
const first = resolveReference(entry["a"], references);
|
|
26723
|
+
const second = resolveReference(entry["b"], references);
|
|
26724
|
+
if (first === null || second === null || first === second) {
|
|
26725
|
+
continue;
|
|
26726
|
+
}
|
|
26727
|
+
const endpoints = violationEndpoints(
|
|
26728
|
+
first,
|
|
26729
|
+
second,
|
|
26730
|
+
assignments,
|
|
26731
|
+
references.records
|
|
26732
|
+
);
|
|
26733
|
+
if (endpoints !== null) {
|
|
26734
|
+
errors.push(
|
|
26735
|
+
`${VIOLATION_PREFIX}: ${endpoints[0]} ran concurrently with conflicting ${endpoints[1]}`
|
|
26736
|
+
);
|
|
26737
|
+
}
|
|
26738
|
+
}
|
|
26739
|
+
return errors;
|
|
26740
|
+
}
|
|
26741
|
+
|
|
26742
|
+
// ../../extensions/drm-copilot/src/lib/validate/parallel-state-records.ts
|
|
26743
|
+
var OPS_REQUIRING_ITEM_KEY = ["add", "remove", "requeue"];
|
|
26744
|
+
var OPS_REQUIRING_NULL_PRIOR_STATE = ["add", "close"];
|
|
26745
|
+
var OPS_REQUIRING_NULL_NEW_STATE = ["close"];
|
|
26746
|
+
function isNone(value) {
|
|
26747
|
+
return value === null || value === void 0;
|
|
26748
|
+
}
|
|
26749
|
+
function resolves(value, issueNums) {
|
|
26750
|
+
return typeof value === "number" && Number.isInteger(value) && issueNums.has(value);
|
|
26751
|
+
}
|
|
26752
|
+
function validateMutationItemKey(entry, entryContext, op, issueNums) {
|
|
26753
|
+
const itemKey = entry["item_key"];
|
|
26754
|
+
if (op === "close") {
|
|
26755
|
+
if (!isNone(itemKey)) {
|
|
26756
|
+
return [
|
|
26757
|
+
`${entryContext} item_key must be null for op 'close'; found: ${pythonRepr9(itemKey)}.`
|
|
26758
|
+
];
|
|
26759
|
+
}
|
|
26760
|
+
return [];
|
|
26761
|
+
}
|
|
26762
|
+
if (isEnumMember(OPS_REQUIRING_ITEM_KEY, op) && !resolves(itemKey, issueNums)) {
|
|
26763
|
+
return [
|
|
26764
|
+
`${entryContext} item_key ${pythonRepr9(itemKey)} does not resolve to an items[].issue_num.`
|
|
26765
|
+
];
|
|
26766
|
+
}
|
|
26767
|
+
return [];
|
|
26768
|
+
}
|
|
26769
|
+
function validateMutationStateField(entry, entryContext, field, op, nullOps) {
|
|
26770
|
+
const value = entry[field];
|
|
26771
|
+
if (isNone(value)) {
|
|
26772
|
+
return [];
|
|
26773
|
+
}
|
|
26774
|
+
if (isEnumMember(nullOps, op)) {
|
|
26775
|
+
return [
|
|
26776
|
+
`${entryContext} ${field} must be null for op ${pythonRepr9(op)}; found: ${pythonRepr9(value)}.`
|
|
26777
|
+
];
|
|
26778
|
+
}
|
|
26779
|
+
if (!isEnumMember(VALID_ITEM_STATES, value)) {
|
|
26780
|
+
return [
|
|
26781
|
+
`${entryContext} ${field} must be null or one of ${VALID_ITEM_STATES.join(", ")}; found: ${pythonRepr9(value)}.`
|
|
26782
|
+
];
|
|
26783
|
+
}
|
|
26784
|
+
return [];
|
|
26785
|
+
}
|
|
26786
|
+
function validateMutationDisposition(entry, entryContext, op) {
|
|
26787
|
+
const disposition = entry["disposition"];
|
|
26788
|
+
if (op === "remove" && entry["prior_state"] === "in_flight") {
|
|
26789
|
+
if (!isEnumMember(VALID_DISPOSITIONS, disposition)) {
|
|
26790
|
+
return [
|
|
26791
|
+
`${entryContext} disposition must be one of ${VALID_DISPOSITIONS.join(", ")} for an in-flight removal; found: ${pythonRepr9(disposition)}.`
|
|
26792
|
+
];
|
|
26793
|
+
}
|
|
26794
|
+
return [];
|
|
26795
|
+
}
|
|
26796
|
+
if (!isNone(disposition)) {
|
|
26797
|
+
return [
|
|
26798
|
+
`${entryContext} disposition must be null unless op is 'remove' with prior_state 'in_flight'; found: ${pythonRepr9(disposition)}.`
|
|
26799
|
+
];
|
|
26800
|
+
}
|
|
26801
|
+
return [];
|
|
26802
|
+
}
|
|
26803
|
+
function validateMutationGeneration(entry, entryContext, recolorGeneration) {
|
|
26804
|
+
const generation = entry["recolor_generation"];
|
|
26805
|
+
if (!isNonNegativeInteger(generation)) {
|
|
26806
|
+
return [
|
|
26807
|
+
`${entryContext} recolor_generation must be a non-negative integer; found: ${pythonRepr9(generation)}.`
|
|
26808
|
+
];
|
|
26809
|
+
}
|
|
26810
|
+
if (isNonNegativeInteger(recolorGeneration) && typeof generation === "number" && typeof recolorGeneration === "number" && generation > recolorGeneration) {
|
|
26811
|
+
return [
|
|
26812
|
+
`${entryContext} recolor_generation ${generation} must not exceed recolor_generation ${recolorGeneration}.`
|
|
26813
|
+
];
|
|
26814
|
+
}
|
|
26815
|
+
return [];
|
|
26816
|
+
}
|
|
26817
|
+
function validateMutations(mutations, issueNums, recolorGeneration, context) {
|
|
26818
|
+
if (!Array.isArray(mutations)) {
|
|
26819
|
+
return [`${context} mutations must be a list.`];
|
|
26820
|
+
}
|
|
26821
|
+
const errors = [];
|
|
26822
|
+
mutations.forEach((entry, position) => {
|
|
26823
|
+
const entryContext = `${context} mutations[${position}]`;
|
|
26824
|
+
if (!isObject14(entry)) {
|
|
26825
|
+
errors.push(`${entryContext} must be an object.`);
|
|
26826
|
+
return;
|
|
26827
|
+
}
|
|
26828
|
+
const op = entry["op"];
|
|
26829
|
+
if (!isEnumMember(VALID_MUTATION_OPS, op)) {
|
|
26830
|
+
errors.push(enumError(entryContext, "op", VALID_MUTATION_OPS, op));
|
|
26831
|
+
}
|
|
26832
|
+
errors.push(...validateMutationItemKey(entry, entryContext, op, issueNums));
|
|
26833
|
+
if (!isNonEmptyString2(entry["at"])) {
|
|
26834
|
+
errors.push(`${entryContext} at must be a non-empty string.`);
|
|
26835
|
+
}
|
|
26836
|
+
errors.push(
|
|
26837
|
+
...validateMutationStateField(
|
|
26838
|
+
entry,
|
|
26839
|
+
entryContext,
|
|
26840
|
+
"prior_state",
|
|
26841
|
+
op,
|
|
26842
|
+
OPS_REQUIRING_NULL_PRIOR_STATE
|
|
26843
|
+
)
|
|
26844
|
+
);
|
|
26845
|
+
errors.push(
|
|
26846
|
+
...validateMutationStateField(
|
|
26847
|
+
entry,
|
|
26848
|
+
entryContext,
|
|
26849
|
+
"new_state",
|
|
26850
|
+
op,
|
|
26851
|
+
OPS_REQUIRING_NULL_NEW_STATE
|
|
26852
|
+
)
|
|
26853
|
+
);
|
|
26854
|
+
errors.push(...validateMutationDisposition(entry, entryContext, op));
|
|
26855
|
+
errors.push(
|
|
26856
|
+
...validateMutationGeneration(entry, entryContext, recolorGeneration)
|
|
26857
|
+
);
|
|
26858
|
+
});
|
|
26859
|
+
return errors;
|
|
26860
|
+
}
|
|
26861
|
+
function validateDriftEvents(events, issueNums, context) {
|
|
26862
|
+
if (!Array.isArray(events)) {
|
|
26863
|
+
return [`${context} drift_events must be a list.`];
|
|
26864
|
+
}
|
|
26865
|
+
const errors = [];
|
|
26866
|
+
events.forEach((entry, position) => {
|
|
26867
|
+
const entryContext = `${context} drift_events[${position}]`;
|
|
26868
|
+
if (!isObject14(entry)) {
|
|
26869
|
+
errors.push(`${entryContext} must be an object.`);
|
|
26870
|
+
return;
|
|
26871
|
+
}
|
|
26872
|
+
const itemKey = entry["item_key"];
|
|
26873
|
+
if (!resolves(itemKey, issueNums)) {
|
|
26874
|
+
errors.push(
|
|
26875
|
+
`${entryContext} item_key ${pythonRepr9(itemKey)} does not resolve to an items[].issue_num.`
|
|
26876
|
+
);
|
|
26877
|
+
}
|
|
26878
|
+
for (const field of ["declared", "observed"]) {
|
|
26879
|
+
if (!isStringList(entry[field])) {
|
|
26880
|
+
errors.push(
|
|
26881
|
+
`${entryContext} ${field} must be a list of non-empty strings.`
|
|
26882
|
+
);
|
|
26883
|
+
}
|
|
26884
|
+
}
|
|
26885
|
+
const escapedPaths = entry["escaped_paths"];
|
|
26886
|
+
if (!isStringList(escapedPaths) || !Array.isArray(escapedPaths) || escapedPaths.length === 0) {
|
|
26887
|
+
errors.push(
|
|
26888
|
+
`${entryContext} escaped_paths must be a non-empty list of non-empty strings.`
|
|
26889
|
+
);
|
|
26890
|
+
}
|
|
26891
|
+
if (!isNonEmptyString2(entry["at"])) {
|
|
26892
|
+
errors.push(`${entryContext} at must be a non-empty string.`);
|
|
26893
|
+
}
|
|
26894
|
+
const action = entry["action"];
|
|
26895
|
+
if (!isEnumMember(VALID_DRIFT_ACTIONS, action)) {
|
|
26896
|
+
errors.push(
|
|
26897
|
+
enumError(entryContext, "action", VALID_DRIFT_ACTIONS, action)
|
|
26898
|
+
);
|
|
26899
|
+
}
|
|
26900
|
+
});
|
|
26901
|
+
return errors;
|
|
26902
|
+
}
|
|
26903
|
+
|
|
26904
|
+
// ../../extensions/drm-copilot/src/lib/validate/parallel-state-structures.ts
|
|
26905
|
+
var COHORT_COVERAGE_EXEMPT_STATES = "withdrawn merged blocked".split(" ");
|
|
26906
|
+
var RECEIPT_ARRAY_KEYS = "delegation_receipts skill_receipts mcp_call_receipts".split(" ");
|
|
26907
|
+
function collectItemKeysAndStates(items) {
|
|
26908
|
+
const pairs = [];
|
|
26909
|
+
if (!Array.isArray(items)) {
|
|
26910
|
+
return pairs;
|
|
26911
|
+
}
|
|
26912
|
+
for (const entry of items) {
|
|
26913
|
+
if (!isObject14(entry)) {
|
|
26914
|
+
continue;
|
|
26915
|
+
}
|
|
26916
|
+
const issueNum = entry["issue_num"];
|
|
26917
|
+
if (typeof issueNum === "number" && Number.isInteger(issueNum) && issueNum > 0) {
|
|
26918
|
+
pairs.push({ issueNum, state: entry["state"] });
|
|
26919
|
+
}
|
|
26920
|
+
}
|
|
26921
|
+
return pairs;
|
|
26922
|
+
}
|
|
26923
|
+
function collectIssueNumbers(items) {
|
|
26924
|
+
return new Set(collectItemKeysAndStates(items).map((pair) => pair.issueNum));
|
|
26925
|
+
}
|
|
26926
|
+
function validateCohortEntry(entry, entryContext, issueNums, recolorGeneration) {
|
|
26927
|
+
const errors = [];
|
|
26928
|
+
const index = entry["index"];
|
|
26929
|
+
if (!isNonNegativeInteger(index)) {
|
|
26930
|
+
errors.push(
|
|
26931
|
+
`${entryContext} index must be a non-negative integer; found: ${pythonRepr9(index)}.`
|
|
26932
|
+
);
|
|
26933
|
+
}
|
|
26934
|
+
const generation = entry["generation"];
|
|
26935
|
+
if (!isNonNegativeInteger(generation)) {
|
|
26936
|
+
errors.push(
|
|
26937
|
+
`${entryContext} generation must be a non-negative integer; found: ${pythonRepr9(generation)}.`
|
|
26938
|
+
);
|
|
26939
|
+
} else if (recolorGeneration !== null && typeof generation === "number" && generation > recolorGeneration) {
|
|
26940
|
+
errors.push(
|
|
26941
|
+
`${entryContext} generation ${generation} must not exceed recolor_generation ${recolorGeneration}.`
|
|
26942
|
+
);
|
|
26943
|
+
}
|
|
26944
|
+
const itemKeys = entry["item_keys"];
|
|
26945
|
+
if (!Array.isArray(itemKeys)) {
|
|
26946
|
+
errors.push(`${entryContext} item_keys must be a list.`);
|
|
26947
|
+
return errors;
|
|
26948
|
+
}
|
|
26949
|
+
for (const key of itemKeys) {
|
|
26950
|
+
if (typeof key !== "number" || !Number.isInteger(key) || !issueNums.has(key)) {
|
|
26951
|
+
errors.push(
|
|
26952
|
+
`${entryContext} item_keys entry ${pythonRepr9(key)} does not resolve to an items[].issue_num.`
|
|
26953
|
+
);
|
|
26954
|
+
}
|
|
26955
|
+
}
|
|
26956
|
+
return errors;
|
|
26957
|
+
}
|
|
26958
|
+
function validateCohortShapes(cohorts, issueNums, recolorGeneration, context) {
|
|
26959
|
+
const errors = [];
|
|
26960
|
+
const generationOk = isNonNegativeInteger(recolorGeneration);
|
|
26961
|
+
if (!generationOk) {
|
|
26962
|
+
errors.push(
|
|
26963
|
+
`${context} recolor_generation must be a non-negative integer; found: ${pythonRepr9(recolorGeneration)}.`
|
|
26964
|
+
);
|
|
26965
|
+
}
|
|
26966
|
+
if (!Array.isArray(cohorts)) {
|
|
26967
|
+
errors.push(`${context} cohorts must be a list.`);
|
|
26968
|
+
return errors;
|
|
26969
|
+
}
|
|
26970
|
+
const bound = generationOk && typeof recolorGeneration === "number" ? recolorGeneration : null;
|
|
26971
|
+
cohorts.forEach((entry, position) => {
|
|
26972
|
+
const entryContext = `${context} cohorts[${position}]`;
|
|
26973
|
+
if (!isObject14(entry)) {
|
|
26974
|
+
errors.push(`${entryContext} must be an object.`);
|
|
26975
|
+
return;
|
|
26976
|
+
}
|
|
26977
|
+
errors.push(...validateCohortEntry(entry, entryContext, issueNums, bound));
|
|
26978
|
+
});
|
|
26979
|
+
return errors;
|
|
26980
|
+
}
|
|
26981
|
+
function currentGenerationCohorts(cohorts, recolorGeneration) {
|
|
26982
|
+
if (!isNonNegativeInteger(recolorGeneration) || !Array.isArray(cohorts)) {
|
|
26983
|
+
return [];
|
|
26984
|
+
}
|
|
26985
|
+
return cohorts.filter(isObject14).filter((entry) => entry["generation"] === recolorGeneration);
|
|
26986
|
+
}
|
|
26987
|
+
function validateCurrentGenerationCohorts(cohorts, items, recolorGeneration, context) {
|
|
26988
|
+
const current = currentGenerationCohorts(cohorts, recolorGeneration);
|
|
26989
|
+
const errors = [];
|
|
26990
|
+
const seenIndices = /* @__PURE__ */ new Set();
|
|
26991
|
+
const duplicateIndices = /* @__PURE__ */ new Set();
|
|
26992
|
+
const membershipCounts = /* @__PURE__ */ new Map();
|
|
26993
|
+
for (const entry of current) {
|
|
26994
|
+
const index = entry["index"];
|
|
26995
|
+
if (isNonNegativeInteger(index) && typeof index === "number") {
|
|
26996
|
+
if (seenIndices.has(index)) {
|
|
26997
|
+
duplicateIndices.add(index);
|
|
26998
|
+
}
|
|
26999
|
+
seenIndices.add(index);
|
|
27000
|
+
}
|
|
27001
|
+
const itemKeys = entry["item_keys"];
|
|
27002
|
+
if (!Array.isArray(itemKeys)) {
|
|
27003
|
+
continue;
|
|
27004
|
+
}
|
|
27005
|
+
for (const key of itemKeys) {
|
|
27006
|
+
if (typeof key === "number" && Number.isInteger(key)) {
|
|
27007
|
+
membershipCounts.set(key, (membershipCounts.get(key) ?? 0) + 1);
|
|
27008
|
+
}
|
|
27009
|
+
}
|
|
27010
|
+
}
|
|
27011
|
+
for (const index of [...duplicateIndices].sort(
|
|
27012
|
+
(left, right) => left - right
|
|
27013
|
+
)) {
|
|
27014
|
+
errors.push(
|
|
27015
|
+
`${context} has duplicate current-generation cohorts[].index: ${index}.`
|
|
27016
|
+
);
|
|
27017
|
+
}
|
|
27018
|
+
const pairs = [...collectItemKeysAndStates(items)].sort(
|
|
27019
|
+
(left, right) => left.issueNum - right.issueNum
|
|
27020
|
+
);
|
|
27021
|
+
for (const { issueNum, state } of pairs) {
|
|
27022
|
+
const count = membershipCounts.get(issueNum) ?? 0;
|
|
27023
|
+
if (count === 1) {
|
|
27024
|
+
continue;
|
|
27025
|
+
}
|
|
27026
|
+
if (count === 0 && isEnumMember(COHORT_COVERAGE_EXEMPT_STATES, state)) {
|
|
27027
|
+
continue;
|
|
27028
|
+
}
|
|
27029
|
+
errors.push(
|
|
27030
|
+
`${context} item ${issueNum} in state ${pythonRepr9(state)} must appear in exactly one current-generation cohort; found ${count}.`
|
|
27031
|
+
);
|
|
27032
|
+
}
|
|
27033
|
+
return errors;
|
|
27034
|
+
}
|
|
27035
|
+
function validateCurrentCohortBound(currentCohort, cohorts, recolorGeneration, context) {
|
|
27036
|
+
if (!isNonNegativeInteger(currentCohort) || typeof currentCohort !== "number") {
|
|
27037
|
+
return [
|
|
27038
|
+
`${context} current_cohort must be a non-negative integer; found: ${pythonRepr9(currentCohort)}.`
|
|
27039
|
+
];
|
|
27040
|
+
}
|
|
27041
|
+
const indices = [];
|
|
27042
|
+
for (const entry of currentGenerationCohorts(cohorts, recolorGeneration)) {
|
|
27043
|
+
const index = entry["index"];
|
|
27044
|
+
if (isNonNegativeInteger(index) && typeof index === "number") {
|
|
27045
|
+
indices.push(index);
|
|
27046
|
+
}
|
|
27047
|
+
}
|
|
27048
|
+
if (indices.length === 0) {
|
|
27049
|
+
return [];
|
|
27050
|
+
}
|
|
27051
|
+
const highest = Math.max(...indices);
|
|
27052
|
+
if (currentCohort > highest) {
|
|
27053
|
+
return [
|
|
27054
|
+
`${context} current_cohort ${currentCohort} must not exceed the maximum current-generation cohorts[].index ${highest}.`
|
|
27055
|
+
];
|
|
27056
|
+
}
|
|
27057
|
+
return [];
|
|
27058
|
+
}
|
|
27059
|
+
function validateEdgeEndpoints(entry, entryContext, issueNums) {
|
|
27060
|
+
const errors = [];
|
|
27061
|
+
const endpoints = /* @__PURE__ */ new Map();
|
|
27062
|
+
for (const field of ["a", "b"]) {
|
|
27063
|
+
const value = entry[field];
|
|
27064
|
+
if (typeof value === "number" && Number.isInteger(value) && issueNums.has(value)) {
|
|
27065
|
+
endpoints.set(field, value);
|
|
27066
|
+
} else {
|
|
27067
|
+
errors.push(
|
|
27068
|
+
`${entryContext} ${field} ${pythonRepr9(value)} does not resolve to an items[].issue_num.`
|
|
27069
|
+
);
|
|
27070
|
+
}
|
|
27071
|
+
}
|
|
27072
|
+
if (endpoints.size !== 2) {
|
|
27073
|
+
return { errors, pair: null };
|
|
27074
|
+
}
|
|
27075
|
+
const first = endpoints.get("a") ?? 0;
|
|
27076
|
+
const second = endpoints.get("b") ?? 0;
|
|
27077
|
+
if (first === second) {
|
|
27078
|
+
errors.push(`${entryContext} endpoints must be distinct; found: ${first}.`);
|
|
27079
|
+
return { errors, pair: null };
|
|
27080
|
+
}
|
|
27081
|
+
if (first > second) {
|
|
27082
|
+
errors.push(
|
|
27083
|
+
`${entryContext} must be normalized with a < b; found: (${first}, ${second}).`
|
|
27084
|
+
);
|
|
27085
|
+
return { errors, pair: null };
|
|
27086
|
+
}
|
|
27087
|
+
return { errors, pair: [first, second] };
|
|
27088
|
+
}
|
|
27089
|
+
function validateConflictEdges(edges, issueNums, context) {
|
|
27090
|
+
if (!Array.isArray(edges)) {
|
|
27091
|
+
return [`${context} conflict_edges must be a list.`];
|
|
27092
|
+
}
|
|
27093
|
+
const errors = [];
|
|
27094
|
+
const seen = /* @__PURE__ */ new Set();
|
|
27095
|
+
const duplicates = /* @__PURE__ */ new Map();
|
|
27096
|
+
edges.forEach((entry, position) => {
|
|
27097
|
+
const entryContext = `${context} conflict_edges[${position}]`;
|
|
27098
|
+
if (!isObject14(entry)) {
|
|
27099
|
+
errors.push(`${entryContext} must be an object.`);
|
|
27100
|
+
return;
|
|
27101
|
+
}
|
|
27102
|
+
const { errors: endpointErrors, pair } = validateEdgeEndpoints(
|
|
27103
|
+
entry,
|
|
27104
|
+
entryContext,
|
|
27105
|
+
issueNums
|
|
27106
|
+
);
|
|
27107
|
+
errors.push(...endpointErrors);
|
|
27108
|
+
const reason = entry["reason"];
|
|
27109
|
+
if (!isEnumMember(VALID_EDGE_REASONS, reason)) {
|
|
27110
|
+
errors.push(
|
|
27111
|
+
enumError(entryContext, "reason", VALID_EDGE_REASONS, reason)
|
|
27112
|
+
);
|
|
27113
|
+
}
|
|
27114
|
+
if (pair === null) {
|
|
27115
|
+
return;
|
|
27116
|
+
}
|
|
27117
|
+
const key = `${pair[0]},${pair[1]}`;
|
|
27118
|
+
if (seen.has(key)) {
|
|
27119
|
+
duplicates.set(key, pair);
|
|
27120
|
+
}
|
|
27121
|
+
seen.add(key);
|
|
27122
|
+
});
|
|
27123
|
+
const ordered = [...duplicates.values()].sort(
|
|
27124
|
+
(left, right) => left[0] - right[0] || left[1] - right[1]
|
|
27125
|
+
);
|
|
27126
|
+
for (const pair of ordered) {
|
|
27127
|
+
errors.push(
|
|
27128
|
+
`${context} has duplicate conflict_edges[] pair: (${pair[0]}, ${pair[1]}).`
|
|
27129
|
+
);
|
|
27130
|
+
}
|
|
27131
|
+
return errors;
|
|
27132
|
+
}
|
|
27133
|
+
function validateReceiptArrays(state, context) {
|
|
27134
|
+
const errors = [];
|
|
27135
|
+
for (const key of RECEIPT_ARRAY_KEYS) {
|
|
27136
|
+
if (key in state && !Array.isArray(state[key])) {
|
|
27137
|
+
errors.push(`${context} ${key} must be a list when present.`);
|
|
27138
|
+
}
|
|
27139
|
+
}
|
|
27140
|
+
return errors;
|
|
27141
|
+
}
|
|
27142
|
+
|
|
27143
|
+
// ../../extensions/drm-copilot/src/lib/validate/parallel-orchestrator-state-core.ts
|
|
27144
|
+
var CONTEXT = "Parallel checkpoint";
|
|
27145
|
+
var EXPECTED_ROUTE_ID2 = "parallel";
|
|
27146
|
+
var MIN_CONCURRENCY = 1;
|
|
27147
|
+
var MAX_CONCURRENCY = 8;
|
|
27148
|
+
var REQUIRED_KEYS4 = [
|
|
27149
|
+
"objective",
|
|
27150
|
+
"completed_steps",
|
|
27151
|
+
"next_step",
|
|
27152
|
+
"last_updated",
|
|
27153
|
+
"route_id",
|
|
27154
|
+
"parallel_slug",
|
|
27155
|
+
"parallel_manifest_path",
|
|
27156
|
+
"parallel_status_doc_path",
|
|
27157
|
+
"mode",
|
|
27158
|
+
"max_concurrency",
|
|
27159
|
+
"current_cohort",
|
|
27160
|
+
"recolor_generation",
|
|
27161
|
+
"cohorts",
|
|
27162
|
+
"items",
|
|
27163
|
+
"conflict_edges",
|
|
27164
|
+
"mutations",
|
|
27165
|
+
"drift_events"
|
|
27166
|
+
];
|
|
27167
|
+
function missingRequiredKeys(state) {
|
|
27168
|
+
return REQUIRED_KEYS4.filter((key) => !(key in state)).map(
|
|
27169
|
+
(key) => `${CONTEXT} missing required key: ${key}.`
|
|
27170
|
+
);
|
|
27171
|
+
}
|
|
27172
|
+
function validateIdentity(state) {
|
|
27173
|
+
const errors = [];
|
|
27174
|
+
const routeId = state["route_id"];
|
|
27175
|
+
if ("route_id" in state && routeId !== EXPECTED_ROUTE_ID2) {
|
|
27176
|
+
errors.push(
|
|
27177
|
+
`${CONTEXT} route_id must be '${EXPECTED_ROUTE_ID2}'; found: ${pythonRepr9(routeId)}.`
|
|
27178
|
+
);
|
|
27179
|
+
}
|
|
27180
|
+
const mode = state["mode"];
|
|
27181
|
+
if ("mode" in state && !isEnumMember(VALID_MODES, mode)) {
|
|
27182
|
+
errors.push(enumError(CONTEXT, "mode", VALID_MODES, mode));
|
|
27183
|
+
}
|
|
27184
|
+
const concurrency = state["max_concurrency"];
|
|
27185
|
+
if ("max_concurrency" in state && !inBoundedRange(concurrency, MIN_CONCURRENCY, MAX_CONCURRENCY)) {
|
|
27186
|
+
errors.push(
|
|
27187
|
+
`${CONTEXT} max_concurrency must be an integer from ${MIN_CONCURRENCY} through ${MAX_CONCURRENCY}; found: ${pythonRepr9(concurrency)}.`
|
|
27188
|
+
);
|
|
27189
|
+
}
|
|
27190
|
+
return errors;
|
|
27191
|
+
}
|
|
27192
|
+
function validateCollections(state) {
|
|
27193
|
+
const items = state["items"];
|
|
27194
|
+
const issueNums = collectIssueNumbers(items);
|
|
27195
|
+
const generation = state["recolor_generation"];
|
|
27196
|
+
const cohorts = state["cohorts"];
|
|
27197
|
+
const errors = [];
|
|
27198
|
+
if ("items" in state) {
|
|
27199
|
+
errors.push(...validateItems(items, CONTEXT));
|
|
27200
|
+
}
|
|
27201
|
+
if ("cohorts" in state) {
|
|
27202
|
+
errors.push(
|
|
27203
|
+
...validateCohortShapes(cohorts, issueNums, generation, CONTEXT)
|
|
27204
|
+
);
|
|
27205
|
+
errors.push(
|
|
27206
|
+
...validateCurrentGenerationCohorts(cohorts, items, generation, CONTEXT)
|
|
27207
|
+
);
|
|
27208
|
+
}
|
|
27209
|
+
if ("current_cohort" in state) {
|
|
27210
|
+
errors.push(
|
|
27211
|
+
...validateCurrentCohortBound(
|
|
27212
|
+
state["current_cohort"],
|
|
27213
|
+
cohorts,
|
|
27214
|
+
generation,
|
|
27215
|
+
CONTEXT
|
|
27216
|
+
)
|
|
27217
|
+
);
|
|
27218
|
+
}
|
|
27219
|
+
if ("conflict_edges" in state) {
|
|
27220
|
+
errors.push(
|
|
27221
|
+
...validateConflictEdges(state["conflict_edges"], issueNums, CONTEXT)
|
|
27222
|
+
);
|
|
27223
|
+
}
|
|
27224
|
+
if ("mutations" in state) {
|
|
27225
|
+
errors.push(
|
|
27226
|
+
...validateMutations(state["mutations"], issueNums, generation, CONTEXT)
|
|
27227
|
+
);
|
|
27228
|
+
}
|
|
27229
|
+
if ("drift_events" in state) {
|
|
27230
|
+
errors.push(
|
|
27231
|
+
...validateDriftEvents(state["drift_events"], issueNums, CONTEXT)
|
|
27232
|
+
);
|
|
27233
|
+
}
|
|
27234
|
+
errors.push(...validateReceiptArrays(state, CONTEXT));
|
|
27235
|
+
return errors;
|
|
27236
|
+
}
|
|
27237
|
+
function recordsCloseMutation(state) {
|
|
27238
|
+
const mutations = state["mutations"];
|
|
27239
|
+
if (!Array.isArray(mutations)) {
|
|
27240
|
+
return false;
|
|
27241
|
+
}
|
|
27242
|
+
return mutations.some(
|
|
27243
|
+
(entry) => isObject14(entry) && entry["op"] === "close"
|
|
27244
|
+
);
|
|
27245
|
+
}
|
|
27246
|
+
function validateCompletion2(state) {
|
|
27247
|
+
const errors = [];
|
|
27248
|
+
const items = state["items"];
|
|
27249
|
+
const entries = Array.isArray(items) ? items : [];
|
|
27250
|
+
entries.forEach((entry, index) => {
|
|
27251
|
+
if (!isObject14(entry)) {
|
|
27252
|
+
return;
|
|
27253
|
+
}
|
|
27254
|
+
if (entry["state"] === "withdrawn") {
|
|
27255
|
+
return;
|
|
27256
|
+
}
|
|
27257
|
+
const mergeStatus = entry["merge_status"];
|
|
27258
|
+
if (!isEnumMember(MERGED_MERGE_STATUSES, mergeStatus)) {
|
|
27259
|
+
errors.push(
|
|
27260
|
+
`${itemContext(CONTEXT, index)} completion validation failed: merge_status is not merged or worktree_removed; found: ${pythonRepr9(mergeStatus)}.`
|
|
27261
|
+
);
|
|
27262
|
+
}
|
|
27263
|
+
});
|
|
27264
|
+
if (state["mode"] === "open" && !recordsCloseMutation(state)) {
|
|
27265
|
+
errors.push(
|
|
27266
|
+
`${CONTEXT} completion validation failed: open mode requires a mutations[] entry with op 'close'.`
|
|
27267
|
+
);
|
|
27268
|
+
}
|
|
27269
|
+
return errors;
|
|
27270
|
+
}
|
|
27271
|
+
function validateParallelOrchestratorStateText(text, options = {}) {
|
|
27272
|
+
let state;
|
|
27273
|
+
try {
|
|
27274
|
+
state = JSON.parse(text);
|
|
27275
|
+
} catch (error2) {
|
|
27276
|
+
const detail = error2 instanceof Error ? error2.message : String(error2);
|
|
27277
|
+
return [`${CONTEXT} is not valid JSON: ${detail}.`];
|
|
27278
|
+
}
|
|
27279
|
+
if (!isObject14(state)) {
|
|
27280
|
+
return [`${CONTEXT} root must be a JSON object.`];
|
|
27281
|
+
}
|
|
27282
|
+
const errors = [];
|
|
27283
|
+
errors.push(...missingRequiredKeys(state));
|
|
27284
|
+
errors.push(...validateIdentity(state));
|
|
27285
|
+
errors.push(...scanProhibitedKeys(state, CONTEXT));
|
|
27286
|
+
errors.push(...validateCollections(state));
|
|
27287
|
+
errors.push(...validateCohortBarrierOrdering(state));
|
|
27288
|
+
if (options.requireComplete === true) {
|
|
27289
|
+
errors.push(...validateCompletion2(state));
|
|
27290
|
+
}
|
|
27291
|
+
return errors;
|
|
27292
|
+
}
|
|
27293
|
+
|
|
27294
|
+
// ../../extensions/drm-copilot/src/lib/validate/parallel-planner-state-core.ts
|
|
27295
|
+
var CONTEXT2 = "Parallel planner checkpoint";
|
|
27296
|
+
var MIN_CONCURRENCY2 = 1;
|
|
27297
|
+
var MAX_CONCURRENCY2 = 8;
|
|
27298
|
+
var REQUIRED_KEYS5 = [
|
|
27299
|
+
"objective",
|
|
27300
|
+
"parallel_slug",
|
|
27301
|
+
"parallel_manifest_path",
|
|
27302
|
+
"mode",
|
|
27303
|
+
"max_concurrency",
|
|
27304
|
+
"items",
|
|
27305
|
+
"cohorts",
|
|
27306
|
+
"conflict_edges",
|
|
27307
|
+
"recolor_generation",
|
|
27308
|
+
"completed_steps",
|
|
27309
|
+
"next_step",
|
|
27310
|
+
"last_updated"
|
|
27311
|
+
];
|
|
27312
|
+
var REQUIRED_ITEM_KEYS = [
|
|
27313
|
+
"issue_num",
|
|
27314
|
+
"feature_folder",
|
|
27315
|
+
"kind",
|
|
27316
|
+
"state",
|
|
27317
|
+
"blast_radius",
|
|
27318
|
+
"preparation_status",
|
|
27319
|
+
"research_path",
|
|
27320
|
+
"plan_path",
|
|
27321
|
+
"preflight_status"
|
|
27322
|
+
];
|
|
27323
|
+
var VALID_COMPLEXITY_BANDS = [
|
|
27324
|
+
"C1",
|
|
27325
|
+
"C2",
|
|
27326
|
+
"C3",
|
|
27327
|
+
"C4"
|
|
27328
|
+
];
|
|
27329
|
+
var READY_NEXT_STEP2 = "PARALLEL_EXECUTION_READY";
|
|
27330
|
+
var READY_PREPARATION_STATUS = "prepared";
|
|
27331
|
+
var READY_PREFLIGHT_STATUS = "PREFLIGHT: ALL CLEAR";
|
|
27332
|
+
var READY_RADIUS_SOURCE = "declared";
|
|
27333
|
+
var MINIMUM_READY_ITEMS = 2;
|
|
27334
|
+
var READY_ITEM_PATH_KEYS = ["research_path", "plan_path"];
|
|
27335
|
+
function kickoffPathFor(slug) {
|
|
27336
|
+
return `artifacts/orchestration/parallel-kickoff-${pythonStr2(slug)}.md`;
|
|
27337
|
+
}
|
|
27338
|
+
function missingRequiredKeys2(state) {
|
|
27339
|
+
return REQUIRED_KEYS5.filter((key) => !(key in state)).map(
|
|
27340
|
+
(key) => `${CONTEXT2} missing required key: ${key}.`
|
|
27341
|
+
);
|
|
27342
|
+
}
|
|
27343
|
+
function validateIdentity2(state) {
|
|
27344
|
+
const errors = [];
|
|
27345
|
+
for (const key of ["parallel_slug", "parallel_manifest_path"]) {
|
|
27346
|
+
if (key in state && !isNonEmptyString2(state[key])) {
|
|
27347
|
+
errors.push(`${CONTEXT2} ${key} must be a non-empty string.`);
|
|
27348
|
+
}
|
|
27349
|
+
}
|
|
27350
|
+
const mode = state["mode"];
|
|
27351
|
+
if ("mode" in state && !isEnumMember(VALID_MODES, mode)) {
|
|
27352
|
+
errors.push(enumError(CONTEXT2, "mode", VALID_MODES, mode));
|
|
27353
|
+
}
|
|
27354
|
+
const concurrency = state["max_concurrency"];
|
|
27355
|
+
if ("max_concurrency" in state && !inBoundedRange(concurrency, MIN_CONCURRENCY2, MAX_CONCURRENCY2)) {
|
|
27356
|
+
errors.push(
|
|
27357
|
+
`${CONTEXT2} max_concurrency must be an integer from ${MIN_CONCURRENCY2} through ${MAX_CONCURRENCY2}; found: ${pythonRepr9(concurrency)}.`
|
|
27358
|
+
);
|
|
27359
|
+
}
|
|
27360
|
+
return errors;
|
|
27361
|
+
}
|
|
27362
|
+
function itemRecords(items) {
|
|
27363
|
+
if (!Array.isArray(items)) {
|
|
27364
|
+
return [];
|
|
27365
|
+
}
|
|
27366
|
+
const records = [];
|
|
27367
|
+
items.forEach((entry, index) => {
|
|
27368
|
+
if (isObject14(entry)) {
|
|
27369
|
+
records.push({ index, record: entry });
|
|
27370
|
+
}
|
|
27371
|
+
});
|
|
27372
|
+
return records;
|
|
27373
|
+
}
|
|
27374
|
+
function validateItemContract(items) {
|
|
27375
|
+
const errors = [];
|
|
27376
|
+
for (const { index, record: record2 } of itemRecords(items)) {
|
|
27377
|
+
const entryContext = itemContext(CONTEXT2, index);
|
|
27378
|
+
for (const key of REQUIRED_ITEM_KEYS) {
|
|
27379
|
+
if (!(key in record2)) {
|
|
27380
|
+
errors.push(`${entryContext} missing required key: ${key}.`);
|
|
27381
|
+
}
|
|
27382
|
+
}
|
|
27383
|
+
const band = record2["complexity_band"];
|
|
27384
|
+
if ("complexity_band" in record2 && !isEnumMember(VALID_COMPLEXITY_BANDS, band)) {
|
|
27385
|
+
errors.push(
|
|
27386
|
+
enumError(
|
|
27387
|
+
entryContext,
|
|
27388
|
+
"complexity_band",
|
|
27389
|
+
VALID_COMPLEXITY_BANDS,
|
|
27390
|
+
band
|
|
27391
|
+
)
|
|
27392
|
+
);
|
|
27393
|
+
}
|
|
27394
|
+
}
|
|
27395
|
+
return errors;
|
|
27396
|
+
}
|
|
27397
|
+
function validateCollections2(state) {
|
|
27398
|
+
const items = state["items"];
|
|
27399
|
+
const issueNums = collectIssueNumbers(items);
|
|
27400
|
+
const generation = state["recolor_generation"];
|
|
27401
|
+
const cohorts = state["cohorts"];
|
|
27402
|
+
const errors = [];
|
|
27403
|
+
if ("items" in state) {
|
|
27404
|
+
errors.push(...validateItems(items, CONTEXT2, true));
|
|
27405
|
+
errors.push(...validateItemContract(items));
|
|
27406
|
+
}
|
|
27407
|
+
if ("cohorts" in state) {
|
|
27408
|
+
errors.push(
|
|
27409
|
+
...validateCohortShapes(cohorts, issueNums, generation, CONTEXT2)
|
|
27410
|
+
);
|
|
27411
|
+
errors.push(
|
|
27412
|
+
...validateCurrentGenerationCohorts(cohorts, items, generation, CONTEXT2)
|
|
27413
|
+
);
|
|
27414
|
+
}
|
|
27415
|
+
if ("current_cohort" in state) {
|
|
27416
|
+
errors.push(
|
|
27417
|
+
...validateCurrentCohortBound(
|
|
27418
|
+
state["current_cohort"],
|
|
27419
|
+
cohorts,
|
|
27420
|
+
generation,
|
|
27421
|
+
CONTEXT2
|
|
27422
|
+
)
|
|
27423
|
+
);
|
|
27424
|
+
}
|
|
27425
|
+
if ("conflict_edges" in state) {
|
|
27426
|
+
errors.push(
|
|
27427
|
+
...validateConflictEdges(state["conflict_edges"], issueNums, CONTEXT2)
|
|
27428
|
+
);
|
|
27429
|
+
}
|
|
27430
|
+
return errors;
|
|
27431
|
+
}
|
|
27432
|
+
function validateReadyItem(record2, entryContext) {
|
|
27433
|
+
const errors = [];
|
|
27434
|
+
const preparationStatus = record2["preparation_status"];
|
|
27435
|
+
if (preparationStatus !== READY_PREPARATION_STATUS) {
|
|
27436
|
+
errors.push(
|
|
27437
|
+
`${entryContext} preparation_status must be ${pythonRepr9(READY_PREPARATION_STATUS)}; found: ${pythonRepr9(preparationStatus)}.`
|
|
27438
|
+
);
|
|
27439
|
+
}
|
|
27440
|
+
const preflightStatus = record2["preflight_status"];
|
|
27441
|
+
if (preflightStatus !== READY_PREFLIGHT_STATUS) {
|
|
27442
|
+
errors.push(
|
|
27443
|
+
`${entryContext} preflight_status must be ${pythonRepr9(READY_PREFLIGHT_STATUS)}; found: ${pythonRepr9(preflightStatus)}.`
|
|
27444
|
+
);
|
|
27445
|
+
}
|
|
27446
|
+
for (const key of READY_ITEM_PATH_KEYS) {
|
|
27447
|
+
if (!isNonEmptyString2(record2[key])) {
|
|
27448
|
+
errors.push(`${entryContext} ${key} must be a non-empty string.`);
|
|
27449
|
+
}
|
|
27450
|
+
}
|
|
27451
|
+
const radius = record2["blast_radius"];
|
|
27452
|
+
const source = isObject14(radius) ? radius["source"] : null;
|
|
27453
|
+
if (source !== READY_RADIUS_SOURCE) {
|
|
27454
|
+
errors.push(
|
|
27455
|
+
`${entryContext} blast_radius.source must be ${pythonRepr9(READY_RADIUS_SOURCE)} for execution readiness; found: ${pythonRepr9(source)}.`
|
|
27456
|
+
);
|
|
27457
|
+
}
|
|
27458
|
+
return errors;
|
|
27459
|
+
}
|
|
27460
|
+
function validateReadyGate(state) {
|
|
27461
|
+
const errors = [];
|
|
27462
|
+
const items = state["items"];
|
|
27463
|
+
if (Array.isArray(items)) {
|
|
27464
|
+
const count = items.length;
|
|
27465
|
+
if (count < MINIMUM_READY_ITEMS) {
|
|
27466
|
+
errors.push(
|
|
27467
|
+
`${CONTEXT2} requires at least ${MINIMUM_READY_ITEMS} items for execution readiness; found: ${count}.`
|
|
27468
|
+
);
|
|
27469
|
+
}
|
|
27470
|
+
for (const { index, record: record2 } of itemRecords(items)) {
|
|
27471
|
+
errors.push(...validateReadyItem(record2, itemContext(CONTEXT2, index)));
|
|
27472
|
+
}
|
|
27473
|
+
}
|
|
27474
|
+
const nextStep = state["next_step"];
|
|
27475
|
+
if (nextStep !== READY_NEXT_STEP2) {
|
|
27476
|
+
errors.push(
|
|
27477
|
+
`${CONTEXT2} next_step must be ${pythonRepr9(READY_NEXT_STEP2)}; found: ${pythonRepr9(nextStep)}.`
|
|
27478
|
+
);
|
|
27479
|
+
}
|
|
27480
|
+
const expectedKickoff = kickoffPathFor(state["parallel_slug"]);
|
|
27481
|
+
const kickoffPromptPath = state["kickoff_prompt_path"];
|
|
27482
|
+
if (kickoffPromptPath !== expectedKickoff) {
|
|
27483
|
+
errors.push(
|
|
27484
|
+
`${CONTEXT2} kickoff_prompt_path must be ${pythonRepr9(expectedKickoff)}; found: ${pythonRepr9(kickoffPromptPath)}.`
|
|
27485
|
+
);
|
|
27486
|
+
}
|
|
27487
|
+
return errors;
|
|
27488
|
+
}
|
|
27489
|
+
function validateParallelPlannerStateText(text, options = {}) {
|
|
27490
|
+
let state;
|
|
27491
|
+
try {
|
|
27492
|
+
state = JSON.parse(text);
|
|
27493
|
+
} catch (error2) {
|
|
27494
|
+
const detail = error2 instanceof Error ? error2.message : String(error2);
|
|
27495
|
+
return [`${CONTEXT2} is not valid JSON: ${detail}.`];
|
|
27496
|
+
}
|
|
27497
|
+
if (!isObject14(state)) {
|
|
27498
|
+
return [`${CONTEXT2} root must be a JSON object.`];
|
|
27499
|
+
}
|
|
27500
|
+
const errors = [];
|
|
27501
|
+
errors.push(...missingRequiredKeys2(state));
|
|
27502
|
+
errors.push(...validateIdentity2(state));
|
|
27503
|
+
errors.push(...scanProhibitedKeys(state, CONTEXT2));
|
|
27504
|
+
errors.push(...validateCollections2(state));
|
|
27505
|
+
if (options.requireReadyForExecution === true) {
|
|
27506
|
+
errors.push(...validateReadyGate(state));
|
|
27507
|
+
}
|
|
27508
|
+
return errors;
|
|
27509
|
+
}
|
|
27510
|
+
|
|
27511
|
+
// ../../extensions/drm-copilot/src/lib/validate/policy-audit-artifact.ts
|
|
27512
|
+
var COVERAGE_PERCENT_RE = /\b\d+(?:\.\d+)?%/;
|
|
27513
|
+
var POLICY_AUDIT_REQUIRED_HEADINGS = [
|
|
27514
|
+
"## Executive Summary",
|
|
27515
|
+
"## 1. General Unit Test Policy Compliance",
|
|
27516
|
+
"## 2. General Code Change Policy Compliance",
|
|
27517
|
+
"## 3. Language-Specific Code Change Policy Compliance",
|
|
27518
|
+
"## 4. Language-Specific Unit Test Policy Compliance",
|
|
27519
|
+
"## 5. Test Coverage Detail",
|
|
27520
|
+
"## 6. Test Execution Metrics",
|
|
27521
|
+
"## 7. Code Quality Checks",
|
|
27522
|
+
"## 8. Gaps and Exceptions",
|
|
27523
|
+
"## 9. Summary of Changes",
|
|
27524
|
+
"## 10. Compliance Verdict",
|
|
27525
|
+
"## Appendix A: Test Inventory",
|
|
27526
|
+
"## Appendix B: Toolchain Commands Reference"
|
|
27527
|
+
];
|
|
27528
|
+
var POLICY_AUDIT_REQUIRED_CHECKLIST_LABELS = [
|
|
27529
|
+
"TypeScript baseline coverage artifact:",
|
|
27530
|
+
"TypeScript post-change coverage artifact:",
|
|
27531
|
+
"PowerShell baseline coverage artifact:",
|
|
27532
|
+
"PowerShell post-change coverage artifact:",
|
|
27533
|
+
"Per-language comparison summary:"
|
|
27534
|
+
];
|
|
27535
|
+
var POLICY_AUDIT_COMPARISON_HEADING = "### 1.2.1 Per-Language Coverage Comparison";
|
|
27536
|
+
var PLACEHOLDER_MARKERS = [
|
|
27537
|
+
"[n]",
|
|
27538
|
+
"[path",
|
|
27539
|
+
"[artifact",
|
|
27540
|
+
"[section reference",
|
|
27541
|
+
"[language]",
|
|
27542
|
+
"tbd",
|
|
27543
|
+
"unverified",
|
|
27544
|
+
"missing"
|
|
27545
|
+
];
|
|
27546
|
+
var TEMPLATE_RESOLVER_TOOL = "resolve_policy_audit_template_asset";
|
|
27547
|
+
var TEMPLATE_RESOLVER_MISSING_MARKERS = [
|
|
27548
|
+
"not exposed",
|
|
27549
|
+
"was not exposed",
|
|
27550
|
+
"missing resolver exposure",
|
|
27551
|
+
"fallback template",
|
|
27552
|
+
"fallback-template"
|
|
27553
|
+
];
|
|
27554
|
+
function hasNumericCoverage(value) {
|
|
27555
|
+
return COVERAGE_PERCENT_RE.test(value);
|
|
27556
|
+
}
|
|
27557
|
+
function isNaValue(value) {
|
|
27558
|
+
return value.trim().toLowerCase().startsWith("n/a");
|
|
27559
|
+
}
|
|
27560
|
+
function hasPlaceholderMarker(value) {
|
|
27561
|
+
const lowered = value.toLowerCase();
|
|
27562
|
+
return PLACEHOLDER_MARKERS.some((marker) => lowered.includes(marker));
|
|
27563
|
+
}
|
|
27564
|
+
function reportsMissingTemplateResolverSuccess(text) {
|
|
27565
|
+
const lowered = text.toLowerCase();
|
|
27566
|
+
if (!lowered.includes(TEMPLATE_RESOLVER_TOOL)) {
|
|
27567
|
+
return false;
|
|
27568
|
+
}
|
|
27569
|
+
if (!TEMPLATE_RESOLVER_MISSING_MARKERS.some((m) => lowered.includes(m))) {
|
|
27570
|
+
return false;
|
|
27571
|
+
}
|
|
27572
|
+
return /\b(pass|ready|readiness)\b/.test(lowered);
|
|
27573
|
+
}
|
|
27574
|
+
function extractPolicyAuditCoverageRows(text) {
|
|
27575
|
+
const rows = [];
|
|
27576
|
+
for (const line of text.split("\n")) {
|
|
27577
|
+
if (!line.startsWith("|")) {
|
|
27578
|
+
continue;
|
|
27579
|
+
}
|
|
27580
|
+
const segments = line.split("|");
|
|
27581
|
+
const cells = segments.slice(1, -1).map((cell) => cell.trim());
|
|
27582
|
+
if (cells.length !== 7) {
|
|
27583
|
+
continue;
|
|
27584
|
+
}
|
|
27585
|
+
const language = cells[0] ?? "";
|
|
27586
|
+
if (language === "Language" || language === "----------" || !language) {
|
|
27587
|
+
continue;
|
|
27588
|
+
}
|
|
27589
|
+
if (language.length > 0 && /^-+$/.test(language)) {
|
|
27590
|
+
continue;
|
|
27591
|
+
}
|
|
27592
|
+
rows.push({
|
|
27593
|
+
Language: language,
|
|
27594
|
+
"Files Changed": cells[1] ?? "",
|
|
27595
|
+
Tests: cells[2] ?? "",
|
|
27596
|
+
"Test Result": cells[3] ?? "",
|
|
27597
|
+
"Baseline Coverage": cells[4] ?? "",
|
|
27598
|
+
"Post-Change Coverage": cells[5] ?? "",
|
|
27599
|
+
"New Code Coverage": cells[6] ?? ""
|
|
27600
|
+
});
|
|
27601
|
+
}
|
|
27602
|
+
return rows;
|
|
27603
|
+
}
|
|
27604
|
+
function findPolicyAuditChecklistLine(text, label) {
|
|
27605
|
+
for (const line of text.split("\n")) {
|
|
27606
|
+
const stripped = line.trim();
|
|
27607
|
+
if (stripped.startsWith("- ") && stripped.includes(label)) {
|
|
27608
|
+
return stripped;
|
|
27609
|
+
}
|
|
27610
|
+
}
|
|
27611
|
+
return null;
|
|
27612
|
+
}
|
|
27613
|
+
function extractPolicyAuditComparisonLines(text) {
|
|
27614
|
+
let inSection = false;
|
|
27615
|
+
const comparisonLines = /* @__PURE__ */ new Map();
|
|
27616
|
+
for (const line of text.split("\n")) {
|
|
27617
|
+
const stripped = line.trim();
|
|
27618
|
+
if (stripped === POLICY_AUDIT_COMPARISON_HEADING) {
|
|
27619
|
+
inSection = true;
|
|
27620
|
+
continue;
|
|
27621
|
+
}
|
|
27622
|
+
if (inSection && stripped.startsWith("### ")) {
|
|
27623
|
+
break;
|
|
27624
|
+
}
|
|
27625
|
+
if (!inSection || !stripped.startsWith("- ")) {
|
|
27626
|
+
continue;
|
|
27627
|
+
}
|
|
27628
|
+
const body = stripped.slice(2);
|
|
27629
|
+
const colonIndex = body.indexOf(":");
|
|
27630
|
+
if (colonIndex === -1) {
|
|
27631
|
+
continue;
|
|
27632
|
+
}
|
|
27633
|
+
const language = body.slice(0, colonIndex);
|
|
27634
|
+
comparisonLines.set(language.trim().toLowerCase(), stripped);
|
|
27635
|
+
}
|
|
27636
|
+
return comparisonLines;
|
|
27637
|
+
}
|
|
27638
|
+
function escapeRegExp3(value) {
|
|
27639
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
27640
|
+
}
|
|
27641
|
+
function comparisonLineHasLabelledPercentage(line, label) {
|
|
27642
|
+
const pattern = new RegExp(`${escapeRegExp3(label)}.*?\\d+(?:\\.\\d+)?%`);
|
|
27643
|
+
return pattern.test(line);
|
|
27644
|
+
}
|
|
27645
|
+
function validatePolicyAuditSubstantiveRequirements(text) {
|
|
27646
|
+
const errors = [];
|
|
27647
|
+
for (const label of POLICY_AUDIT_REQUIRED_CHECKLIST_LABELS) {
|
|
27648
|
+
const line = findPolicyAuditChecklistLine(text, label);
|
|
27649
|
+
if (line === null) {
|
|
27650
|
+
errors.push(`Policy audit missing required checklist line: ${label}`);
|
|
27651
|
+
continue;
|
|
27652
|
+
}
|
|
27653
|
+
if (hasPlaceholderMarker(line)) {
|
|
27654
|
+
errors.push(
|
|
27655
|
+
`Policy audit checklist line still contains placeholder text: ${label}`
|
|
27656
|
+
);
|
|
27657
|
+
}
|
|
27658
|
+
}
|
|
27659
|
+
const coverageRows = extractPolicyAuditCoverageRows(text);
|
|
27660
|
+
if (coverageRows.length === 0) {
|
|
27661
|
+
errors.push("Policy audit missing coverage metrics table rows.");
|
|
27662
|
+
}
|
|
27663
|
+
if (!text.includes(POLICY_AUDIT_COMPARISON_HEADING)) {
|
|
27664
|
+
errors.push(
|
|
27665
|
+
`Policy audit missing required heading: ${POLICY_AUDIT_COMPARISON_HEADING}`
|
|
27666
|
+
);
|
|
27667
|
+
}
|
|
27668
|
+
const comparisonLines = extractPolicyAuditComparisonLines(text);
|
|
27669
|
+
for (const row of coverageRows) {
|
|
27670
|
+
const language = row.Language;
|
|
27671
|
+
const baseline = row["Baseline Coverage"];
|
|
27672
|
+
const postChange = row["Post-Change Coverage"];
|
|
27673
|
+
const newCode = row["New Code Coverage"];
|
|
27674
|
+
const requiresCoverageComparison = [baseline, postChange, newCode].some(
|
|
27675
|
+
(value) => !isNaValue(value)
|
|
27676
|
+
);
|
|
27677
|
+
if (!isNaValue(baseline) && !hasNumericCoverage(baseline)) {
|
|
27678
|
+
errors.push(
|
|
27679
|
+
`Policy audit missing numeric baseline coverage for ${language}.`
|
|
27680
|
+
);
|
|
27681
|
+
}
|
|
27682
|
+
if (!isNaValue(postChange) && !hasNumericCoverage(postChange)) {
|
|
27683
|
+
errors.push(
|
|
27684
|
+
`Policy audit missing numeric post-change coverage for ${language}.`
|
|
27685
|
+
);
|
|
27686
|
+
}
|
|
27687
|
+
if (!isNaValue(newCode) && !hasNumericCoverage(newCode)) {
|
|
27688
|
+
errors.push(
|
|
27689
|
+
`Policy audit missing numeric new/changed-code coverage for ${language}.`
|
|
27690
|
+
);
|
|
27691
|
+
}
|
|
27692
|
+
if (!requiresCoverageComparison) {
|
|
27693
|
+
continue;
|
|
27694
|
+
}
|
|
27695
|
+
const comparisonLine = comparisonLines.get(language.toLowerCase());
|
|
27696
|
+
if (comparisonLine === void 0) {
|
|
27697
|
+
errors.push(
|
|
27698
|
+
`Policy audit missing per-language comparison line for ${language}.`
|
|
27699
|
+
);
|
|
27700
|
+
continue;
|
|
27701
|
+
}
|
|
27702
|
+
if (!comparisonLineHasLabelledPercentage(comparisonLine, "Baseline:")) {
|
|
27703
|
+
errors.push(
|
|
27704
|
+
`Policy audit comparison line missing numeric baseline for ${language}.`
|
|
27705
|
+
);
|
|
27706
|
+
}
|
|
27707
|
+
if (!comparisonLineHasLabelledPercentage(comparisonLine, "Post-change:")) {
|
|
26245
27708
|
errors.push(
|
|
26246
27709
|
`Policy audit comparison line missing numeric post-change coverage for ${language}.`
|
|
26247
27710
|
);
|
|
@@ -26342,7 +27805,7 @@ function validatePlanText(text) {
|
|
|
26342
27805
|
const seenPhases = [];
|
|
26343
27806
|
const expectedTaskNum = /* @__PURE__ */ new Map();
|
|
26344
27807
|
let foundTask = false;
|
|
26345
|
-
const lines = text.split(
|
|
27808
|
+
const lines = text.split(/\r\n|\n|\r/);
|
|
26346
27809
|
lines.forEach((line, lineIndex) => {
|
|
26347
27810
|
const lineNumber = lineIndex + 1;
|
|
26348
27811
|
if (line.startsWith("### Phase ")) {
|
|
@@ -26449,6 +27912,20 @@ function validateArtifact(input) {
|
|
|
26449
27912
|
}
|
|
26450
27913
|
case "epic-kickoff":
|
|
26451
27914
|
return validateEpicKickoffText(input.text);
|
|
27915
|
+
case "parallel-orchestrator-state": {
|
|
27916
|
+
const options = {
|
|
27917
|
+
...input.requireComplete === void 0 ? {} : { requireComplete: input.requireComplete }
|
|
27918
|
+
};
|
|
27919
|
+
return validateParallelOrchestratorStateText(input.text, options);
|
|
27920
|
+
}
|
|
27921
|
+
case "parallel-planner-state": {
|
|
27922
|
+
const options = {
|
|
27923
|
+
...input.requireReadyForExecution === void 0 ? {} : { requireReadyForExecution: input.requireReadyForExecution }
|
|
27924
|
+
};
|
|
27925
|
+
return validateParallelPlannerStateText(input.text, options);
|
|
27926
|
+
}
|
|
27927
|
+
case "parallel-kickoff":
|
|
27928
|
+
return validateParallelKickoffText(input.text);
|
|
26452
27929
|
default:
|
|
26453
27930
|
return [`Unsupported artifact type: ${input.artifactType}`];
|
|
26454
27931
|
}
|