@danmoisan/drm-copilot-mcp 1.0.21 → 1.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/out/mcp-server.js +1730 -139
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/MEMORY.md +5 -1
  4. package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_commit_push_memory_before_pr.md +48 -2
  5. package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_no_sendmessage_tool.md +35 -0
  6. package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_worktree_isolation_branches_from_main.md +45 -0
  7. package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +257 -0
  8. package/resources/claude-customizations/.claude/agents/parallel-planner.md +183 -0
  9. package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +23 -11
  10. package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +259 -0
  11. package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +499 -0
  12. package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate-helpers.ps1 +302 -0
  13. package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +359 -0
  14. package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +244 -0
  15. package/resources/claude-customizations/.claude/lib/bash/compute-cohorts.sh +143 -0
  16. package/resources/claude-customizations/.claude/lib/bash/compute-concurrency-batches.sh +122 -0
  17. package/resources/claude-customizations/.claude/lib/bash/parallel-cohorts.sh +330 -0
  18. package/resources/claude-customizations/.claude/lib/bash/parallel-common.sh +238 -0
  19. package/resources/claude-customizations/.claude/lib/bash/parallel-items-validate.sh +244 -0
  20. package/resources/claude-customizations/.claude/lib/bash/parallel-manifest-validate.sh +187 -0
  21. package/resources/claude-customizations/.claude/lib/bash/parallel-yaml-emit.sh +340 -0
  22. package/resources/claude-customizations/.claude/lib/bash/parallel-yaml-scan.sh +335 -0
  23. package/resources/claude-customizations/.claude/lib/bash/validate-parallel-manifest.sh +134 -0
  24. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +379 -0
  25. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConfig.psm1 +491 -0
  26. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +490 -0
  27. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusGlob.psm1 +429 -0
  28. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusValidation.psm1 +366 -0
  29. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +184 -0
  30. package/resources/claude-customizations/.claude/rules/shell.md +7 -2
  31. package/resources/claude-customizations/.claude/settings.json +28 -0
  32. package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +152 -0
  33. package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +93 -0
  34. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +971 -0
  35. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +461 -0
  36. package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +176 -0
  37. package/resources/claude-customizations/.claude/skills/parallel-run/SKILL.md +56 -0
  38. package/resources/claude-customizations/config/blast-radius.json +16 -0
  39. package/resources/claude-customizations/config/orchestration-routing.json +355 -0
  40. package/resources/claude-customizations/pack-manifests/core.json +32 -1
  41. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  42. package/resources/config/orchestration-routing.json +22 -0
  43. 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
- validateItems(() => gen.assign(validArr, false));
1799
+ validateItems2(() => gen.assign(validArr, false));
1800
1800
  return validArr;
1801
1801
  }
1802
1802
  gen.var(valid, true);
1803
- validateItems(() => gen.break());
1803
+ validateItems2(() => gen.break());
1804
1804
  return valid;
1805
- function validateItems(notValid) {
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({
@@ -5246,10 +5246,10 @@ var require_additionalItems = __commonJS({
5246
5246
  cxt.pass((0, codegen_1._)`${len} <= ${items.length}`);
5247
5247
  } else if (typeof schema == "object" && !(0, util_1.alwaysValidSchema)(it, schema)) {
5248
5248
  const valid = gen.var("valid", (0, codegen_1._)`${len} <= ${items.length}`);
5249
- gen.if((0, codegen_1.not)(valid), () => validateItems(valid));
5249
+ gen.if((0, codegen_1.not)(valid), () => validateItems2(valid));
5250
5250
  cxt.ok(valid);
5251
5251
  }
5252
- function validateItems(valid) {
5252
+ function validateItems2(valid) {
5253
5253
  gen.forRange("i", items.length, len, (i) => {
5254
5254
  cxt.subschema({ keyword, dataProp: i, dataPropType: util_1.Type.Num }, valid);
5255
5255
  if (!it.allErrors)
@@ -5421,7 +5421,7 @@ var require_contains = __commonJS({
5421
5421
  it.items = true;
5422
5422
  const valid = gen.name("valid");
5423
5423
  if (max === void 0 && min === 1) {
5424
- validateItems(valid, () => gen.if(valid, () => gen.break()));
5424
+ validateItems2(valid, () => gen.if(valid, () => gen.break()));
5425
5425
  } else if (min === 0) {
5426
5426
  gen.let(valid, true);
5427
5427
  if (max !== void 0)
@@ -5434,9 +5434,9 @@ var require_contains = __commonJS({
5434
5434
  function validateItemsWithCount() {
5435
5435
  const schValid = gen.name("_valid");
5436
5436
  const count = gen.let("count", 0);
5437
- validateItems(schValid, () => gen.if(schValid, () => checkLimits(count)));
5437
+ validateItems2(schValid, () => gen.if(schValid, () => checkLimits(count)));
5438
5438
  }
5439
- function validateItems(_valid, block) {
5439
+ function validateItems2(_valid, block) {
5440
5440
  gen.forRange("i", 0, len, (i) => {
5441
5441
  cxt.subschema({
5442
5442
  keyword: "contains",
@@ -8990,13 +8990,13 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
8990
8990
  }
8991
8991
  return propValues;
8992
8992
  });
8993
- const isObject14 = isObject;
8993
+ const isObject15 = isObject;
8994
8994
  const catchall = def.catchall;
8995
8995
  let value;
8996
8996
  inst._zod.parse = (payload, ctx) => {
8997
8997
  value ?? (value = _normalized.value);
8998
8998
  const input = payload.value;
8999
- if (!isObject14(input)) {
8999
+ if (!isObject15(input)) {
9000
9000
  payload.issues.push({
9001
9001
  expected: "object",
9002
9002
  code: "invalid_type",
@@ -9123,7 +9123,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
9123
9123
  return (payload, ctx) => fn(shape, payload, ctx);
9124
9124
  };
9125
9125
  let fastpass;
9126
- const isObject14 = isObject;
9126
+ const isObject15 = isObject;
9127
9127
  const jit = !globalConfig.jitless;
9128
9128
  const allowsEval2 = allowsEval;
9129
9129
  const fastEnabled = jit && allowsEval2.value;
@@ -9132,7 +9132,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
9132
9132
  inst._zod.parse = (payload, ctx) => {
9133
9133
  value ?? (value = _normalized.value);
9134
9134
  const input = payload.value;
9135
- if (!isObject14(input)) {
9135
+ if (!isObject15(input)) {
9136
9136
  payload.issues.push({
9137
9137
  expected: "object",
9138
9138
  code: "invalid_type",
@@ -15089,16 +15089,7 @@ var Server = class extends Protocol {
15089
15089
  if (!methodSchema) {
15090
15090
  throw new Error("Schema is missing a method literal");
15091
15091
  }
15092
- let methodValue;
15093
- if (isZ4Schema(methodSchema)) {
15094
- const v4Schema = methodSchema;
15095
- const v4Def = v4Schema._zod?.def;
15096
- methodValue = v4Def?.value ?? v4Schema.value;
15097
- } else {
15098
- const v3Schema = methodSchema;
15099
- const legacyDef = v3Schema._def;
15100
- methodValue = legacyDef?.value ?? v3Schema.value;
15101
- }
15092
+ const methodValue = getLiteralValue(methodSchema);
15102
15093
  if (typeof methodValue !== "string") {
15103
15094
  throw new Error("Schema method literal must be a string");
15104
15095
  }
@@ -15407,8 +15398,17 @@ var Server = class extends Protocol {
15407
15398
  var import_node_process = __toESM(require("node:process"), 1);
15408
15399
 
15409
15400
  // node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
15401
+ var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
15410
15402
  var ReadBuffer = class {
15403
+ constructor(options) {
15404
+ this._maxBufferSize = options?.maxBufferSize ?? STDIO_DEFAULT_MAX_BUFFER_SIZE;
15405
+ }
15411
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
+ }
15412
15412
  this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
15413
15413
  }
15414
15414
  readMessage() {
@@ -15436,18 +15436,24 @@ function serializeMessage(message) {
15436
15436
 
15437
15437
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
15438
15438
  var StdioServerTransport = class {
15439
- 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) {
15440
15440
  this._stdin = _stdin;
15441
15441
  this._stdout = _stdout;
15442
- this._readBuffer = new ReadBuffer();
15443
15442
  this._started = false;
15444
15443
  this._ondata = (chunk) => {
15445
- this._readBuffer.append(chunk);
15446
- this.processReadBuffer();
15444
+ try {
15445
+ this._readBuffer.append(chunk);
15446
+ this.processReadBuffer();
15447
+ } catch (error2) {
15448
+ this.onerror?.(error2);
15449
+ this.close().catch(() => {
15450
+ });
15451
+ }
15447
15452
  };
15448
15453
  this._onerror = (error2) => {
15449
15454
  this.onerror?.(error2);
15450
15455
  };
15456
+ this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize });
15451
15457
  }
15452
15458
  /**
15453
15459
  * Starts listening for messages on stdin.
@@ -16262,7 +16268,10 @@ var VALID_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
16262
16268
  "orchestrator-state",
16263
16269
  "epic-orchestrator-state",
16264
16270
  "epic-planner-state",
16265
- "epic-kickoff"
16271
+ "epic-kickoff",
16272
+ "parallel-orchestrator-state",
16273
+ "parallel-planner-state",
16274
+ "parallel-kickoff"
16266
16275
  ]);
16267
16276
  function resolveValidateOrchestrationArtifactsToolInput(rawInput, fallbackWorkspaceRoot) {
16268
16277
  const args = asToolArgumentObject(rawInput);
@@ -17007,7 +17016,10 @@ var REPO_AUTOMATION_TOOL_DEFINITIONS = [
17007
17016
  "orchestrator-state",
17008
17017
  "epic-orchestrator-state",
17009
17018
  "epic-planner-state",
17010
- "epic-kickoff"
17019
+ "epic-kickoff",
17020
+ "parallel-orchestrator-state",
17021
+ "parallel-planner-state",
17022
+ "parallel-kickoff"
17011
17023
  ],
17012
17024
  description: "The type of orchestration artifact to validate."
17013
17025
  },
@@ -17017,7 +17029,7 @@ var REPO_AUTOMATION_TOOL_DEFINITIONS = [
17017
17029
  },
17018
17030
  require_complete: {
17019
17031
  type: "boolean",
17020
- description: "When true and artifact_type is 'orchestrator-state' or 'epic-orchestrator-state', require all phases to be complete."
17032
+ description: "When true and artifact_type is 'orchestrator-state', 'epic-orchestrator-state', or 'parallel-orchestrator-state', require all phases to be complete."
17021
17033
  },
17022
17034
  require_model_routing: {
17023
17035
  type: "boolean",
@@ -17033,7 +17045,7 @@ var REPO_AUTOMATION_TOOL_DEFINITIONS = [
17033
17045
  },
17034
17046
  require_ready_for_execution: {
17035
17047
  type: "boolean",
17036
- 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."
17037
17049
  }
17038
17050
  },
17039
17051
  required: ["workspace_root", "artifact_type", "artifact_path"],
@@ -18799,9 +18811,161 @@ var ExcludingFileSystem = class {
18799
18811
  }
18800
18812
  };
18801
18813
 
18814
+ // ../../extensions/drm-copilot/src/lib/push-down/claude-routing-merge.ts
18815
+ var ROUTES_KEY = "routes";
18816
+ var AUTHORITATIVE_ROUTE = "parallel";
18817
+ var RoutingMergeError = class extends Error {
18818
+ /** Destination path whose current content could not be parsed. */
18819
+ path;
18820
+ /**
18821
+ * @param path Destination path that failed to parse.
18822
+ * @param detail Parser detail appended to the message.
18823
+ */
18824
+ constructor(path11, detail) {
18825
+ super(
18826
+ `Destination routing document is not valid JSON and was not written: ${path11} (${detail})`
18827
+ );
18828
+ this.name = "RoutingMergeError";
18829
+ this.path = path11;
18830
+ }
18831
+ };
18832
+ function normalizePosix4(value) {
18833
+ return value.replace(/\\/g, "/").replace(/\/+$/, "");
18834
+ }
18835
+ function relativeToPosix4(path11, root) {
18836
+ const normalizedPath = normalizePosix4(path11);
18837
+ const normalizedRoot = normalizePosix4(root);
18838
+ if (normalizedPath === normalizedRoot) {
18839
+ return "";
18840
+ }
18841
+ const prefix = `${normalizedRoot}/`;
18842
+ return normalizedPath.startsWith(prefix) ? normalizedPath.slice(prefix.length) : null;
18843
+ }
18844
+ function parseRoutingObject(text, path11) {
18845
+ let parsed;
18846
+ try {
18847
+ parsed = JSON.parse(text);
18848
+ } catch (error2) {
18849
+ const detail = error2 instanceof Error ? error2.message : String(error2);
18850
+ throw new RoutingMergeError(path11, detail);
18851
+ }
18852
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
18853
+ throw new RoutingMergeError(path11, "document root is not a JSON object");
18854
+ }
18855
+ return parsed;
18856
+ }
18857
+ function asObject(value) {
18858
+ if (value === void 0 || value === null || typeof value !== "object") {
18859
+ return null;
18860
+ }
18861
+ return Array.isArray(value) ? null : value;
18862
+ }
18863
+ function mergeRoutes(destinationRoutes, sourceRoutes) {
18864
+ const merged = {};
18865
+ if (destinationRoutes !== null) {
18866
+ for (const [name, definition] of Object.entries(destinationRoutes)) {
18867
+ const sourceDefinition = sourceRoutes?.[name];
18868
+ merged[name] = name === AUTHORITATIVE_ROUTE && sourceDefinition !== void 0 ? sourceDefinition : definition;
18869
+ }
18870
+ }
18871
+ if (sourceRoutes !== null) {
18872
+ for (const [name, definition] of Object.entries(sourceRoutes)) {
18873
+ if (!(name in merged)) {
18874
+ merged[name] = definition;
18875
+ }
18876
+ }
18877
+ }
18878
+ return merged;
18879
+ }
18880
+ function mergeRoutingDocuments(destinationText, sourceText, path11) {
18881
+ const destination = parseRoutingObject(destinationText, path11);
18882
+ const source = parseRoutingObject(sourceText, path11);
18883
+ const merged = {};
18884
+ for (const [key, value] of Object.entries(destination)) {
18885
+ merged[key] = key === ROUTES_KEY ? mergeRoutes(asObject(value), asObject(source[ROUTES_KEY])) : value;
18886
+ }
18887
+ for (const [key, value] of Object.entries(source)) {
18888
+ if (key in merged) {
18889
+ continue;
18890
+ }
18891
+ merged[key] = key === ROUTES_KEY ? mergeRoutes(null, asObject(value)) : value;
18892
+ }
18893
+ return `${JSON.stringify(merged, null, 2)}
18894
+ `;
18895
+ }
18896
+ var RoutingMergeFileSystem = class {
18897
+ inner;
18898
+ destinationRoot;
18899
+ mergeRelativePath;
18900
+ /**
18901
+ * @param inner The wrapped adapter performing real I/O.
18902
+ * @param destinationRoot Destination workspace root (POSIX path).
18903
+ * @param mergeRelativePath Destination-relative path to merge.
18904
+ */
18905
+ constructor(inner, destinationRoot, mergeRelativePath) {
18906
+ this.inner = inner;
18907
+ this.destinationRoot = normalizePosix4(destinationRoot);
18908
+ this.mergeRelativePath = mergeRelativePath;
18909
+ }
18910
+ /** @inheritdoc */
18911
+ listFiles(root) {
18912
+ return this.inner.listFiles(root);
18913
+ }
18914
+ /** @inheritdoc */
18915
+ isDir(path11) {
18916
+ return this.inner.isDir(path11);
18917
+ }
18918
+ /** @inheritdoc */
18919
+ isFile(path11) {
18920
+ return this.inner.isFile(path11);
18921
+ }
18922
+ /** @inheritdoc */
18923
+ readTextFile(path11) {
18924
+ return this.inner.readTextFile(path11);
18925
+ }
18926
+ /** @inheritdoc */
18927
+ ensureDir(path11) {
18928
+ this.inner.ensureDir(path11);
18929
+ }
18930
+ /**
18931
+ * Write a file, merging the one configured routing path when it exists.
18932
+ *
18933
+ * @param path Absolute destination POSIX path.
18934
+ * @param content Source content the engine wants to publish.
18935
+ * @throws RoutingMergeError When the destination routing document is not
18936
+ * parseable; the destination bytes are left untouched.
18937
+ */
18938
+ writeTextFile(path11, content) {
18939
+ if (!this.isMergeTarget(path11)) {
18940
+ this.inner.writeTextFile(path11, content);
18941
+ return;
18942
+ }
18943
+ if (!this.inner.isFile(path11)) {
18944
+ this.inner.writeTextFile(path11, content);
18945
+ return;
18946
+ }
18947
+ const merged = mergeRoutingDocuments(
18948
+ this.inner.readTextFile(path11),
18949
+ content,
18950
+ path11
18951
+ );
18952
+ this.inner.writeTextFile(path11, merged);
18953
+ }
18954
+ /**
18955
+ * Return whether a destination path is the configured merge target.
18956
+ *
18957
+ * @param path Absolute destination POSIX path.
18958
+ * @returns True when the path resolves to the merge-target relative path.
18959
+ */
18960
+ isMergeTarget(path11) {
18961
+ return relativeToPosix4(path11, this.destinationRoot) === this.mergeRelativePath;
18962
+ }
18963
+ };
18964
+
18802
18965
  // ../../extensions/drm-copilot/src/lib/push-down/claude-customizations.ts
18803
18966
  var ARTIFACT_DIRECTORY4 = "artifacts/claude-customizations";
18804
- var ROOT_FOLDERS2 = [".claude"];
18967
+ var ROOT_FOLDERS2 = [".claude", "config"];
18968
+ var ROUTING_MERGE_RELATIVE_PATH = "config/orchestration-routing.json";
18805
18969
  var EXCLUDED_RELATIVE_PATHS = [
18806
18970
  ".claude/settings.local.json"
18807
18971
  ];
@@ -18850,8 +19014,13 @@ function pushDownCustomizations4(options) {
18850
19014
  effectiveBundle,
18851
19015
  fs9
18852
19016
  );
18853
- const excludingFs = new ExcludingFileSystem(
19017
+ const mergingFs = new RoutingMergeFileSystem(
18854
19018
  fs9,
19019
+ destinationRoot,
19020
+ ROUTING_MERGE_RELATIVE_PATH
19021
+ );
19022
+ const excludingFs = new ExcludingFileSystem(
19023
+ mergingFs,
18855
19024
  repoRoot,
18856
19025
  EXCLUDED_RELATIVE_PATHS,
18857
19026
  {
@@ -26088,121 +26257,1529 @@ function validateOrchestratorStateText(text, options = {}) {
26088
26257
  return errors;
26089
26258
  }
26090
26259
 
26091
- // ../../extensions/drm-copilot/src/lib/validate/policy-audit-artifact.ts
26092
- var COVERAGE_PERCENT_RE = /\b\d+(?:\.\d+)?%/;
26093
- var POLICY_AUDIT_REQUIRED_HEADINGS = [
26094
- "## Executive Summary",
26095
- "## 1. General Unit Test Policy Compliance",
26096
- "## 2. General Code Change Policy Compliance",
26097
- "## 3. Language-Specific Code Change Policy Compliance",
26098
- "## 4. Language-Specific Unit Test Policy Compliance",
26099
- "## 5. Test Coverage Detail",
26100
- "## 6. Test Execution Metrics",
26101
- "## 7. Code Quality Checks",
26102
- "## 8. Gaps and Exceptions",
26103
- "## 9. Summary of Changes",
26104
- "## 10. Compliance Verdict",
26105
- "## Appendix A: Test Inventory",
26106
- "## Appendix B: Toolchain Commands Reference"
26107
- ];
26108
- var POLICY_AUDIT_REQUIRED_CHECKLIST_LABELS = [
26109
- "TypeScript baseline coverage artifact:",
26110
- "TypeScript post-change coverage artifact:",
26111
- "PowerShell baseline coverage artifact:",
26112
- "PowerShell post-change coverage artifact:",
26113
- "Per-language comparison summary:"
26114
- ];
26115
- var POLICY_AUDIT_COMPARISON_HEADING = "### 1.2.1 Per-Language Coverage Comparison";
26116
- var PLACEHOLDER_MARKERS = [
26117
- "[n]",
26118
- "[path",
26119
- "[artifact",
26120
- "[section reference",
26121
- "[language]",
26122
- "tbd",
26123
- "unverified",
26124
- "missing"
26125
- ];
26126
- var TEMPLATE_RESOLVER_TOOL = "resolve_policy_audit_template_asset";
26127
- var TEMPLATE_RESOLVER_MISSING_MARKERS = [
26128
- "not exposed",
26129
- "was not exposed",
26130
- "missing resolver exposure",
26131
- "fallback template",
26132
- "fallback-template"
26260
+ // ../../extensions/drm-copilot/src/lib/validate/parallel-kickoff-artifact.ts
26261
+ var KICKOFF_HEADING_RE2 = /^# Parallel Kickoff: (?<slug>[a-z0-9][a-z0-9-]*)$/;
26262
+ var PARALLEL_RUN_RE = /Run `\/parallel-run (?<slug>[a-z0-9][a-z0-9-]*)`/;
26263
+ var MANIFEST_RE2 = /docs\/features\/parallel\/[a-z0-9][a-z0-9-]*\/parallel\.md/;
26264
+ var PLAN_BRANCH_RE = /parallel\/[a-z0-9][a-z0-9-]*-plan/;
26265
+ 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;
26266
+ var INTEGRITY_COMMIT_RE2 = /^(?:-\s*)?planning_commit:\s*`?(?<commit>[0-9a-fA-F]{7,64})`?\s*$/;
26267
+ var LINE_SPLIT_RE = /\r\n|\r|\n/u;
26268
+ var ITEM_HEADERS = [
26269
+ "issue_num",
26270
+ "feature_folder",
26271
+ "cohort",
26272
+ "complexity",
26273
+ "branch",
26274
+ "plan-path"
26133
26275
  ];
26134
- function hasNumericCoverage(value) {
26135
- return COVERAGE_PERCENT_RE.test(value);
26276
+ var HASH_HEADERS2 = /* @__PURE__ */ new Set([
26277
+ "plan-hash",
26278
+ "plan_hash",
26279
+ "git-blob-sha",
26280
+ "git_blob_sha"
26281
+ ]);
26282
+ var COMPLEXITY_BANDS2 = /* @__PURE__ */ new Set(["C1", "C2", "C3", "C4"]);
26283
+ function splitSections3(text) {
26284
+ const sections = /* @__PURE__ */ new Map();
26285
+ const errors = [];
26286
+ let current;
26287
+ for (const line of text.split(LINE_SPLIT_RE).slice(1)) {
26288
+ if (line.startsWith("## ")) {
26289
+ current = line.slice(3).trim();
26290
+ if (sections.has(current)) {
26291
+ errors.push(
26292
+ `Parallel kickoff contains duplicate section: ## ${current}`
26293
+ );
26294
+ } else {
26295
+ sections.set(current, []);
26296
+ }
26297
+ continue;
26298
+ }
26299
+ if (current !== void 0) {
26300
+ sections.get(current)?.push(line);
26301
+ }
26302
+ }
26303
+ for (const required2 of ["Invocation Prompt", "Item Summary"]) {
26304
+ if (!sections.has(required2)) {
26305
+ errors.push(
26306
+ `Parallel kickoff is missing required section: ## ${required2}`
26307
+ );
26308
+ }
26309
+ }
26310
+ return { sections, errors };
26136
26311
  }
26137
- function isNaValue(value) {
26138
- return value.trim().toLowerCase().startsWith("n/a");
26312
+ function parseCells2(line) {
26313
+ const stripped = line.trim();
26314
+ if (!stripped.startsWith("|") || !stripped.endsWith("|")) {
26315
+ return void 0;
26316
+ }
26317
+ return stripped.slice(1, -1).split("|").map((cell) => cell.trim().replace(/^`|`$/g, ""));
26139
26318
  }
26140
- function hasPlaceholderMarker(value) {
26141
- const lowered = value.toLowerCase();
26142
- return PLACEHOLDER_MARKERS.some((marker) => lowered.includes(marker));
26319
+ function isSeparator2(cells) {
26320
+ return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/.test(cell));
26143
26321
  }
26144
- function reportsMissingTemplateResolverSuccess(text) {
26145
- const lowered = text.toLowerCase();
26146
- if (!lowered.includes(TEMPLATE_RESOLVER_TOOL)) {
26147
- return false;
26322
+ function tableRows2(lines, expectedHeaders) {
26323
+ const nonempty = lines.filter((line) => line.trim().length > 0);
26324
+ if (nonempty.length < 2) {
26325
+ return {
26326
+ rows: [],
26327
+ errors: [
26328
+ "Parallel kickoff table is missing its header or separator row."
26329
+ ]
26330
+ };
26148
26331
  }
26149
- if (!TEMPLATE_RESOLVER_MISSING_MARKERS.some((m) => lowered.includes(m))) {
26150
- return false;
26332
+ const headers = parseCells2(nonempty[0] ?? "");
26333
+ const separator = parseCells2(nonempty[1] ?? "");
26334
+ const errors = [];
26335
+ if (headers === void 0 || headers.length !== expectedHeaders.length || headers.some((value, index) => value !== expectedHeaders[index])) {
26336
+ errors.push(
26337
+ `Parallel kickoff item table headers must be: ${expectedHeaders.join(" | ")}`
26338
+ );
26339
+ }
26340
+ if (separator === void 0 || separator.length !== expectedHeaders.length || !isSeparator2(separator)) {
26341
+ errors.push("Parallel kickoff table separator row is invalid.");
26151
26342
  }
26152
- return /\b(pass|ready|readiness)\b/.test(lowered);
26153
- }
26154
- function extractPolicyAuditCoverageRows(text) {
26155
26343
  const rows = [];
26156
- for (const line of text.split("\n")) {
26157
- if (!line.startsWith("|")) {
26158
- continue;
26159
- }
26160
- const segments = line.split("|");
26161
- const cells = segments.slice(1, -1).map((cell) => cell.trim());
26162
- if (cells.length !== 7) {
26163
- continue;
26164
- }
26165
- const language = cells[0] ?? "";
26166
- if (language === "Language" || language === "----------" || !language) {
26167
- continue;
26168
- }
26169
- if (language.length > 0 && /^-+$/.test(language)) {
26170
- continue;
26344
+ for (const line of nonempty.slice(2)) {
26345
+ const cells = parseCells2(line);
26346
+ if (cells === void 0 || cells.length !== expectedHeaders.length) {
26347
+ errors.push(`Parallel kickoff table row is invalid: ${line}`);
26348
+ } else {
26349
+ rows.push(cells);
26171
26350
  }
26172
- rows.push({
26173
- Language: language,
26174
- "Files Changed": cells[1] ?? "",
26175
- Tests: cells[2] ?? "",
26176
- "Test Result": cells[3] ?? "",
26177
- "Baseline Coverage": cells[4] ?? "",
26178
- "Post-Change Coverage": cells[5] ?? "",
26179
- "New Code Coverage": cells[6] ?? ""
26180
- });
26181
26351
  }
26182
- return rows;
26183
- }
26184
- function findPolicyAuditChecklistLine(text, label) {
26185
- for (const line of text.split("\n")) {
26186
- const stripped = line.trim();
26187
- if (stripped.startsWith("- ") && stripped.includes(label)) {
26188
- return stripped;
26189
- }
26352
+ if (rows.length === 0) {
26353
+ errors.push(
26354
+ "Parallel kickoff item table must contain at least one item row."
26355
+ );
26190
26356
  }
26191
- return null;
26357
+ return { rows, errors };
26192
26358
  }
26193
- function extractPolicyAuditComparisonLines(text) {
26194
- let inSection = false;
26195
- const comparisonLines = /* @__PURE__ */ new Map();
26196
- for (const line of text.split("\n")) {
26197
- const stripped = line.trim();
26198
- if (stripped === POLICY_AUDIT_COMPARISON_HEADING) {
26199
- inSection = true;
26200
- continue;
26359
+ function parseItems(lines) {
26360
+ const table = tableRows2(lines, ITEM_HEADERS);
26361
+ const items = [];
26362
+ table.rows.forEach((row, index) => {
26363
+ const issueNum = Number(row[0]);
26364
+ if (!Number.isInteger(issueNum)) {
26365
+ table.errors.push(
26366
+ `Parallel kickoff item row ${String(index)} issue_num must be an integer.`
26367
+ );
26368
+ return;
26201
26369
  }
26202
- if (inSection && stripped.startsWith("### ")) {
26203
- break;
26370
+ const cohort = Number(row[2]);
26371
+ if (!Number.isInteger(cohort)) {
26372
+ table.errors.push(
26373
+ `Parallel kickoff item row ${String(index)} cohort must be an integer.`
26374
+ );
26375
+ return;
26204
26376
  }
26205
- if (!inSection || !stripped.startsWith("- ")) {
26377
+ const complexity = row[3] ?? "";
26378
+ if (!COMPLEXITY_BANDS2.has(complexity)) {
26379
+ table.errors.push(
26380
+ `Parallel kickoff item row ${String(index)} complexity must be C1-C4.`
26381
+ );
26382
+ }
26383
+ items.push({
26384
+ issueNum,
26385
+ featureFolder: row[1] ?? "",
26386
+ cohort,
26387
+ complexity,
26388
+ branch: row[4] ?? "",
26389
+ planPath: row[5] ?? ""
26390
+ });
26391
+ });
26392
+ return { items, errors: table.errors };
26393
+ }
26394
+ function parseIntegrityTable(tableLines) {
26395
+ const planHashes = {};
26396
+ const errors = [];
26397
+ const header = parseCells2(tableLines[0] ?? "");
26398
+ if (header === void 0 || header.length !== 2 || header[0] !== "plan-path" || !HASH_HEADERS2.has(header[1] ?? "")) {
26399
+ errors.push(
26400
+ "Parallel kickoff integrity table headers must be plan-path and plan-hash."
26401
+ );
26402
+ } else if (tableLines.length < 2) {
26403
+ errors.push(
26404
+ "Parallel kickoff integrity table is missing its separator row."
26405
+ );
26406
+ } else {
26407
+ const separator = parseCells2(tableLines[1] ?? "");
26408
+ if (separator === void 0 || separator.length !== 2 || !isSeparator2(separator)) {
26409
+ errors.push("Parallel kickoff integrity table separator row is invalid.");
26410
+ }
26411
+ for (const line of tableLines.slice(2)) {
26412
+ const cells = parseCells2(line);
26413
+ if (cells === void 0 || cells.length !== 2 || !/^[0-9a-fA-F]{40,64}$/.test(cells[1] ?? "")) {
26414
+ errors.push(`Parallel kickoff integrity table row is invalid: ${line}`);
26415
+ continue;
26416
+ }
26417
+ const planPath = cells[0] ?? "";
26418
+ if (planHashes[planPath] !== void 0) {
26419
+ errors.push(
26420
+ `Parallel kickoff integrity repeats plan path: '${planPath}'.`
26421
+ );
26422
+ }
26423
+ planHashes[planPath] = (cells[1] ?? "").toLowerCase();
26424
+ }
26425
+ }
26426
+ return { planHashes, errors };
26427
+ }
26428
+ function parseIntegrity2(lines) {
26429
+ let planningCommit;
26430
+ const errors = [];
26431
+ const tableLines = [];
26432
+ for (const line of lines) {
26433
+ if (line.trim().length === 0) {
26434
+ continue;
26435
+ }
26436
+ const match = INTEGRITY_COMMIT_RE2.exec(line.trim());
26437
+ if (match?.groups?.["commit"] !== void 0) {
26438
+ if (planningCommit !== void 0) {
26439
+ errors.push(
26440
+ "Parallel kickoff integrity has duplicate planning_commit fields."
26441
+ );
26442
+ }
26443
+ planningCommit = match.groups["commit"].toLowerCase();
26444
+ } else if (line.trim().startsWith("|")) {
26445
+ tableLines.push(line);
26446
+ } else {
26447
+ errors.push(`Parallel kickoff integrity line is invalid: ${line}`);
26448
+ }
26449
+ }
26450
+ let planHashes = {};
26451
+ if (tableLines.length > 0) {
26452
+ const table = parseIntegrityTable(tableLines);
26453
+ planHashes = table.planHashes;
26454
+ errors.push(...table.errors);
26455
+ }
26456
+ return {
26457
+ ...planningCommit === void 0 ? {} : { planningCommit },
26458
+ planHashes,
26459
+ errors
26460
+ };
26461
+ }
26462
+ function parseParallelKickoff(text) {
26463
+ const lines = text.split(LINE_SPLIT_RE);
26464
+ if (text.length === 0) {
26465
+ return { errors: ["Parallel kickoff is empty."] };
26466
+ }
26467
+ const heading = KICKOFF_HEADING_RE2.exec(lines[0] ?? "");
26468
+ if (heading?.groups?.["slug"] === void 0) {
26469
+ return {
26470
+ errors: [
26471
+ "Parallel kickoff first line must match '# Parallel Kickoff: <slug>'."
26472
+ ]
26473
+ };
26474
+ }
26475
+ const sectionResult = splitSections3(text);
26476
+ const invocation = (sectionResult.sections.get("Invocation Prompt") ?? []).join("\n");
26477
+ const invocationSlug = PARALLEL_RUN_RE.exec(invocation)?.groups?.["slug"];
26478
+ const manifestMatch = MANIFEST_RE2.exec(invocation);
26479
+ const branchMatch = PLAN_BRANCH_RE.exec(invocation);
26480
+ const resumeMatch = RESUME_RE2.exec(invocation);
26481
+ if (invocationSlug === void 0) {
26482
+ sectionResult.errors.push(
26483
+ "Parallel kickoff invocation must contain `Run /parallel-run <slug>`."
26484
+ );
26485
+ }
26486
+ if (manifestMatch?.[0] === void 0 || branchMatch?.[0] === void 0 || resumeMatch === null) {
26487
+ sectionResult.errors.push(
26488
+ "Parallel kickoff invocation must structurally name the manifest, plan-home branch, and atomic-execution resume boundary."
26489
+ );
26490
+ }
26491
+ const itemResult = parseItems(
26492
+ sectionResult.sections.get("Item Summary") ?? []
26493
+ );
26494
+ sectionResult.errors.push(...itemResult.errors);
26495
+ const integrity = parseIntegrity2(
26496
+ sectionResult.sections.get("Integrity") ?? []
26497
+ );
26498
+ sectionResult.errors.push(...integrity.errors);
26499
+ if (sectionResult.errors.length > 0 || invocationSlug === void 0 || manifestMatch?.[0] === void 0 || branchMatch?.[0] === void 0 || resumeMatch === null) {
26500
+ return { errors: sectionResult.errors };
26501
+ }
26502
+ return {
26503
+ parsed: {
26504
+ slug: heading.groups["slug"],
26505
+ invocationSlug,
26506
+ manifestPath: manifestMatch[0],
26507
+ planHomeBranch: branchMatch[0],
26508
+ items: itemResult.items,
26509
+ ...integrity.planningCommit === void 0 ? {} : { planningCommit: integrity.planningCommit },
26510
+ planHashes: integrity.planHashes
26511
+ },
26512
+ errors: []
26513
+ };
26514
+ }
26515
+ function validateParallelKickoffText(text) {
26516
+ return parseParallelKickoff(text).errors;
26517
+ }
26518
+
26519
+ // ../../extensions/drm-copilot/src/lib/validate/parallel-state-shared.ts
26520
+ function words(text) {
26521
+ return text.split(" ");
26522
+ }
26523
+ var VALID_ITEM_STATES = words(
26524
+ "proposed admitted prepared scheduled in_flight merged withdrawn blocked"
26525
+ );
26526
+ var VALID_MERGE_STATUS2 = words(
26527
+ "not_started worktree_created pr_open ci_green merged worktree_removed blocked_drift blocked_ci_loop_limit"
26528
+ );
26529
+ var VALID_SOURCES = words("derived declared observed");
26530
+ var VALID_KINDS = words("feature bug");
26531
+ var VALID_MODES = words("closed open");
26532
+ var VALID_MUTATION_OPS = words("add remove close requeue");
26533
+ var VALID_DISPOSITIONS = words("detach abandon");
26534
+ var VALID_EDGE_REASONS = words(
26535
+ "path_overlap module_overlap shared_surface_overlap contract_dependency"
26536
+ );
26537
+ var VALID_DRIFT_ACTIONS = words(
26538
+ "raised_blocking_finding halted_later_started_item"
26539
+ );
26540
+ var MERGED_MERGE_STATUSES = words("merged worktree_removed");
26541
+ var BLOCKED_MERGE_STATUSES = words(
26542
+ "blocked_drift blocked_ci_loop_limit"
26543
+ );
26544
+ var BLAST_RADIUS_LIST_FIELDS = words(
26545
+ "paths modules shared_surfaces contracts"
26546
+ );
26547
+ var PROHIBITED_ANY_LEVEL_KEYS = words(
26548
+ "depends_on integration_branch epic_merge_pr"
26549
+ );
26550
+ var ROOT_PATH = "<root>";
26551
+ function isObject14(value) {
26552
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26553
+ }
26554
+ function pythonRepr9(value) {
26555
+ if (value === null || value === void 0) {
26556
+ return "None";
26557
+ }
26558
+ if (typeof value === "boolean") {
26559
+ return value ? "True" : "False";
26560
+ }
26561
+ if (typeof value === "string") {
26562
+ return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
26563
+ }
26564
+ if (Array.isArray(value)) {
26565
+ return `[${value.map(pythonRepr9).join(", ")}]`;
26566
+ }
26567
+ if (isObject14(value)) {
26568
+ const pairs = Object.entries(value).map(
26569
+ ([key, item]) => `${pythonRepr9(key)}: ${pythonRepr9(item)}`
26570
+ );
26571
+ return `{${pairs.join(", ")}}`;
26572
+ }
26573
+ return String(value);
26574
+ }
26575
+ function pythonStr2(value) {
26576
+ return typeof value === "string" ? value : pythonRepr9(value);
26577
+ }
26578
+ function isEnumMember(members, value) {
26579
+ return typeof value === "string" && members.includes(value);
26580
+ }
26581
+ function isNonEmptyString2(value) {
26582
+ return typeof value === "string" && value.trim().length > 0;
26583
+ }
26584
+ function isIntegral(value) {
26585
+ return typeof value === "number" && Number.isInteger(value);
26586
+ }
26587
+ function isPositiveInteger(value) {
26588
+ return isIntegral(value) && value > 0;
26589
+ }
26590
+ function isNonNegativeInteger(value) {
26591
+ return isIntegral(value) && value >= 0;
26592
+ }
26593
+ function isStringList(value) {
26594
+ return Array.isArray(value) && value.every(isNonEmptyString2);
26595
+ }
26596
+ function inBoundedRange(value, minimum, maximum) {
26597
+ return isIntegral(value) && value >= minimum && value <= maximum;
26598
+ }
26599
+ function enumError(context, field, members, value) {
26600
+ return `${context} ${field} must be one of ${members.join(", ")}; found: ${pythonRepr9(value)}.`;
26601
+ }
26602
+ function itemContext(context, index) {
26603
+ return `${context} items[${index}]`;
26604
+ }
26605
+ function validateBlastRadiusBlock(radius, context) {
26606
+ if (!isObject14(radius)) {
26607
+ return [`${context} blast_radius must be an object.`];
26608
+ }
26609
+ const errors = [];
26610
+ for (const field of BLAST_RADIUS_LIST_FIELDS) {
26611
+ if (!isStringList(radius[field])) {
26612
+ errors.push(
26613
+ `${context} blast_radius.${field} must be a list of non-empty strings.`
26614
+ );
26615
+ }
26616
+ }
26617
+ const source = radius["source"];
26618
+ if (!isEnumMember(VALID_SOURCES, source)) {
26619
+ errors.push(
26620
+ enumError(context, "blast_radius.source", VALID_SOURCES, source)
26621
+ );
26622
+ }
26623
+ if (!isNonEmptyString2(radius["computed_at"])) {
26624
+ errors.push(
26625
+ `${context} blast_radius.computed_at must be a non-empty string.`
26626
+ );
26627
+ }
26628
+ return errors;
26629
+ }
26630
+ function validateMergeStatus(record2, context, state) {
26631
+ if (!("merge_status" in record2)) {
26632
+ return [];
26633
+ }
26634
+ const mergeStatus = record2["merge_status"];
26635
+ if (!isEnumMember(VALID_MERGE_STATUS2, mergeStatus)) {
26636
+ return [
26637
+ enumError(context, "merge_status", VALID_MERGE_STATUS2, mergeStatus)
26638
+ ];
26639
+ }
26640
+ if (isEnumMember(MERGED_MERGE_STATUSES, mergeStatus) && state !== "merged") {
26641
+ return [
26642
+ `${context} merge_status ${pythonRepr9(mergeStatus)} requires state 'merged'; found: ${pythonRepr9(state)}.`
26643
+ ];
26644
+ }
26645
+ if (isEnumMember(BLOCKED_MERGE_STATUSES, mergeStatus) && state !== "blocked") {
26646
+ return [
26647
+ `${context} merge_status ${pythonRepr9(mergeStatus)} requires state 'blocked'; found: ${pythonRepr9(state)}.`
26648
+ ];
26649
+ }
26650
+ return [];
26651
+ }
26652
+ function validateItemRecord(item, context, requireKind = false) {
26653
+ if (!isObject14(item)) {
26654
+ return [`${context} must be an object.`];
26655
+ }
26656
+ const errors = [];
26657
+ const issueNum = item["issue_num"];
26658
+ if (!isPositiveInteger(issueNum)) {
26659
+ errors.push(
26660
+ `${context} issue_num must be a positive integer; found: ${pythonRepr9(issueNum)}.`
26661
+ );
26662
+ }
26663
+ if (!isNonEmptyString2(item["feature_folder"])) {
26664
+ errors.push(`${context} feature_folder must be a non-empty string.`);
26665
+ }
26666
+ const state = item["state"];
26667
+ if (!isEnumMember(VALID_ITEM_STATES, state)) {
26668
+ errors.push(enumError(context, "state", VALID_ITEM_STATES, state));
26669
+ }
26670
+ if (requireKind) {
26671
+ const kind = item["kind"];
26672
+ if (!isEnumMember(VALID_KINDS, kind)) {
26673
+ errors.push(enumError(context, "kind", VALID_KINDS, kind));
26674
+ }
26675
+ }
26676
+ errors.push(...validateMergeStatus(item, context, state));
26677
+ errors.push(...validateBlastRadiusBlock(item["blast_radius"], context));
26678
+ return errors;
26679
+ }
26680
+ function validateItems(items, context, requireKind = false) {
26681
+ if (!Array.isArray(items)) {
26682
+ return [`${context} items must be a list.`];
26683
+ }
26684
+ const errors = [];
26685
+ const seen = /* @__PURE__ */ new Set();
26686
+ const duplicates = /* @__PURE__ */ new Set();
26687
+ items.forEach((entry, index) => {
26688
+ errors.push(
26689
+ ...validateItemRecord(entry, itemContext(context, index), requireKind)
26690
+ );
26691
+ if (!isObject14(entry)) {
26692
+ return;
26693
+ }
26694
+ const issueNum = entry["issue_num"];
26695
+ if (typeof issueNum !== "number" || !Number.isInteger(issueNum)) {
26696
+ return;
26697
+ }
26698
+ if (seen.has(issueNum)) {
26699
+ duplicates.add(issueNum);
26700
+ }
26701
+ seen.add(issueNum);
26702
+ });
26703
+ for (const issueNum of [...duplicates].sort((left, right) => left - right)) {
26704
+ errors.push(`${context} has duplicate items[].issue_num: ${issueNum}.`);
26705
+ }
26706
+ return errors;
26707
+ }
26708
+ function prohibitedKeyErrors(value, path11, context, keys) {
26709
+ const errors = [];
26710
+ if (isObject14(value)) {
26711
+ for (const [key, child] of Object.entries(value)) {
26712
+ if (keys.includes(key)) {
26713
+ errors.push(`${context} carries prohibited key '${key}' at ${path11}.`);
26714
+ }
26715
+ const childPath = path11 === ROOT_PATH ? key : `${path11}.${key}`;
26716
+ errors.push(...prohibitedKeyErrors(child, childPath, context, keys));
26717
+ }
26718
+ } else if (Array.isArray(value)) {
26719
+ value.forEach((entry, index) => {
26720
+ errors.push(
26721
+ ...prohibitedKeyErrors(entry, `${path11}[${index}]`, context, keys)
26722
+ );
26723
+ });
26724
+ }
26725
+ return errors;
26726
+ }
26727
+ function scanProhibitedKeys(root, context, deepKeys = PROHIBITED_ANY_LEVEL_KEYS, topLevelKeys = []) {
26728
+ const errors = prohibitedKeyErrors(root, ROOT_PATH, context, deepKeys);
26729
+ if (isObject14(root) && topLevelKeys.length > 0) {
26730
+ for (const key of topLevelKeys) {
26731
+ if (key in root) {
26732
+ errors.push(
26733
+ `${context} carries prohibited key '${key}' at ${ROOT_PATH}.`
26734
+ );
26735
+ }
26736
+ }
26737
+ }
26738
+ return errors;
26739
+ }
26740
+
26741
+ // ../../extensions/drm-copilot/src/lib/validate/parallel-orchestrator-state-cohort-barrier.ts
26742
+ var VIOLATION_PREFIX = "PARALLEL_COHORT_BARRIER_VIOLATION";
26743
+ var ITEM_START_TIMESTAMP_FIELD = "worktree_created_at";
26744
+ var MERGE_CONFIRMATION_TIMESTAMP_FIELD = "merged_at";
26745
+ var NOT_STARTED_MERGE_STATUS = "not_started";
26746
+ var GATING_KEYS = ["conflict_edges", "cohorts"];
26747
+ var FOLDER_HINT_PREFIXES = [
26748
+ "docs/features/active/",
26749
+ "docs/features/completed/",
26750
+ "active/",
26751
+ "completed/"
26752
+ ];
26753
+ function normalizeFolderHint2(value) {
26754
+ for (const prefix of FOLDER_HINT_PREFIXES) {
26755
+ if (value.startsWith(prefix)) {
26756
+ return value.slice(prefix.length);
26757
+ }
26758
+ }
26759
+ return value;
26760
+ }
26761
+ function buildReferenceIndex(items) {
26762
+ const records = /* @__PURE__ */ new Map();
26763
+ const byFolderHint = /* @__PURE__ */ new Map();
26764
+ if (!Array.isArray(items)) {
26765
+ return { records, byFolderHint };
26766
+ }
26767
+ for (const entry of items) {
26768
+ if (!isObject14(entry)) {
26769
+ continue;
26770
+ }
26771
+ const issueNum = entry["issue_num"];
26772
+ if (typeof issueNum !== "number" || !isPositiveInteger(issueNum)) {
26773
+ continue;
26774
+ }
26775
+ if (!records.has(issueNum)) {
26776
+ records.set(issueNum, entry);
26777
+ }
26778
+ const folder = entry["feature_folder"];
26779
+ if (typeof folder === "string" && folder.trim().length > 0) {
26780
+ const hint = normalizeFolderHint2(folder);
26781
+ if (!byFolderHint.has(hint)) {
26782
+ byFolderHint.set(hint, issueNum);
26783
+ }
26784
+ }
26785
+ }
26786
+ return { records, byFolderHint };
26787
+ }
26788
+ function resolveReference(reference, references) {
26789
+ if (typeof reference === "string") {
26790
+ return references.byFolderHint.get(normalizeFolderHint2(reference)) ?? null;
26791
+ }
26792
+ if (typeof reference === "number" && isPositiveInteger(reference) && references.records.has(reference)) {
26793
+ return reference;
26794
+ }
26795
+ return null;
26796
+ }
26797
+ function cohortIndexByItem(cohorts, recolorGeneration, references) {
26798
+ const assignments = /* @__PURE__ */ new Map();
26799
+ if (!Array.isArray(cohorts) || !isNonNegativeInteger(recolorGeneration)) {
26800
+ return assignments;
26801
+ }
26802
+ for (const entry of cohorts) {
26803
+ if (!isObject14(entry) || entry["generation"] !== recolorGeneration) {
26804
+ continue;
26805
+ }
26806
+ const cohortIndex = entry["index"];
26807
+ const itemKeys = entry["item_keys"];
26808
+ if (typeof cohortIndex !== "number" || !isNonNegativeInteger(cohortIndex) || !Array.isArray(itemKeys)) {
26809
+ continue;
26810
+ }
26811
+ for (const reference of itemKeys) {
26812
+ const key = resolveReference(reference, references);
26813
+ if (key !== null && !assignments.has(key)) {
26814
+ assignments.set(key, cohortIndex);
26815
+ }
26816
+ }
26817
+ }
26818
+ return assignments;
26819
+ }
26820
+ function hasStarted(record2) {
26821
+ const start = record2[ITEM_START_TIMESTAMP_FIELD];
26822
+ if (typeof start === "string" && start.trim().length > 0) {
26823
+ return true;
26824
+ }
26825
+ const mergeStatus = record2["merge_status"];
26826
+ return typeof mergeStatus === "string" && mergeStatus !== NOT_STARTED_MERGE_STATUS;
26827
+ }
26828
+ function satisfiesBarrier(record2) {
26829
+ return isEnumMember(MERGED_MERGE_STATUSES, record2["merge_status"]);
26830
+ }
26831
+ function mergeConfirmedAfterStart(earlier, later) {
26832
+ const confirmed = earlier[MERGE_CONFIRMATION_TIMESTAMP_FIELD];
26833
+ const started = later[ITEM_START_TIMESTAMP_FIELD];
26834
+ if (typeof confirmed !== "string" || typeof started !== "string") {
26835
+ return false;
26836
+ }
26837
+ return confirmed > started;
26838
+ }
26839
+ function violationEndpoints(first, second, assignments, records) {
26840
+ const firstIndex = assignments.get(first);
26841
+ const secondIndex = assignments.get(second);
26842
+ if (firstIndex !== void 0 && firstIndex === secondIndex) {
26843
+ return [first, second];
26844
+ }
26845
+ if (firstIndex === void 0 || secondIndex === void 0) {
26846
+ return null;
26847
+ }
26848
+ const [earlierKey, laterKey] = firstIndex < secondIndex ? [first, second] : [second, first];
26849
+ const earlier = records.get(earlierKey);
26850
+ const later = records.get(laterKey);
26851
+ if (earlier === void 0 || later === void 0) {
26852
+ return null;
26853
+ }
26854
+ const statusViolation = hasStarted(later) && !satisfiesBarrier(earlier);
26855
+ if (statusViolation || mergeConfirmedAfterStart(earlier, later)) {
26856
+ return [earlierKey, laterKey];
26857
+ }
26858
+ return null;
26859
+ }
26860
+ function validateCohortBarrierOrdering(state) {
26861
+ if (GATING_KEYS.some((key) => !(key in state))) {
26862
+ return [];
26863
+ }
26864
+ const edges = state["conflict_edges"];
26865
+ if (!Array.isArray(edges)) {
26866
+ return [];
26867
+ }
26868
+ const references = buildReferenceIndex(state["items"]);
26869
+ const assignments = cohortIndexByItem(
26870
+ state["cohorts"],
26871
+ state["recolor_generation"],
26872
+ references
26873
+ );
26874
+ const errors = [];
26875
+ for (const entry of edges) {
26876
+ if (!isObject14(entry)) {
26877
+ continue;
26878
+ }
26879
+ const first = resolveReference(entry["a"], references);
26880
+ const second = resolveReference(entry["b"], references);
26881
+ if (first === null || second === null || first === second) {
26882
+ continue;
26883
+ }
26884
+ const endpoints = violationEndpoints(
26885
+ first,
26886
+ second,
26887
+ assignments,
26888
+ references.records
26889
+ );
26890
+ if (endpoints !== null) {
26891
+ errors.push(
26892
+ `${VIOLATION_PREFIX}: ${endpoints[0]} ran concurrently with conflicting ${endpoints[1]}`
26893
+ );
26894
+ }
26895
+ }
26896
+ return errors;
26897
+ }
26898
+
26899
+ // ../../extensions/drm-copilot/src/lib/validate/parallel-state-records.ts
26900
+ var OPS_REQUIRING_ITEM_KEY = ["add", "remove", "requeue"];
26901
+ var OPS_REQUIRING_NULL_PRIOR_STATE = ["add", "close"];
26902
+ var OPS_REQUIRING_NULL_NEW_STATE = ["close"];
26903
+ function isNone(value) {
26904
+ return value === null || value === void 0;
26905
+ }
26906
+ function resolves(value, issueNums) {
26907
+ return typeof value === "number" && Number.isInteger(value) && issueNums.has(value);
26908
+ }
26909
+ function validateMutationItemKey(entry, entryContext, op, issueNums) {
26910
+ const itemKey = entry["item_key"];
26911
+ if (op === "close") {
26912
+ if (!isNone(itemKey)) {
26913
+ return [
26914
+ `${entryContext} item_key must be null for op 'close'; found: ${pythonRepr9(itemKey)}.`
26915
+ ];
26916
+ }
26917
+ return [];
26918
+ }
26919
+ if (isEnumMember(OPS_REQUIRING_ITEM_KEY, op) && !resolves(itemKey, issueNums)) {
26920
+ return [
26921
+ `${entryContext} item_key ${pythonRepr9(itemKey)} does not resolve to an items[].issue_num.`
26922
+ ];
26923
+ }
26924
+ return [];
26925
+ }
26926
+ function validateMutationStateField(entry, entryContext, field, op, nullOps) {
26927
+ const value = entry[field];
26928
+ if (isNone(value)) {
26929
+ return [];
26930
+ }
26931
+ if (isEnumMember(nullOps, op)) {
26932
+ return [
26933
+ `${entryContext} ${field} must be null for op ${pythonRepr9(op)}; found: ${pythonRepr9(value)}.`
26934
+ ];
26935
+ }
26936
+ if (!isEnumMember(VALID_ITEM_STATES, value)) {
26937
+ return [
26938
+ `${entryContext} ${field} must be null or one of ${VALID_ITEM_STATES.join(", ")}; found: ${pythonRepr9(value)}.`
26939
+ ];
26940
+ }
26941
+ return [];
26942
+ }
26943
+ function validateMutationDisposition(entry, entryContext, op) {
26944
+ const disposition = entry["disposition"];
26945
+ if (op === "remove" && entry["prior_state"] === "in_flight") {
26946
+ if (!isEnumMember(VALID_DISPOSITIONS, disposition)) {
26947
+ return [
26948
+ `${entryContext} disposition must be one of ${VALID_DISPOSITIONS.join(", ")} for an in-flight removal; found: ${pythonRepr9(disposition)}.`
26949
+ ];
26950
+ }
26951
+ return [];
26952
+ }
26953
+ if (!isNone(disposition)) {
26954
+ return [
26955
+ `${entryContext} disposition must be null unless op is 'remove' with prior_state 'in_flight'; found: ${pythonRepr9(disposition)}.`
26956
+ ];
26957
+ }
26958
+ return [];
26959
+ }
26960
+ function validateMutationGeneration(entry, entryContext, recolorGeneration) {
26961
+ const generation = entry["recolor_generation"];
26962
+ if (!isNonNegativeInteger(generation)) {
26963
+ return [
26964
+ `${entryContext} recolor_generation must be a non-negative integer; found: ${pythonRepr9(generation)}.`
26965
+ ];
26966
+ }
26967
+ if (isNonNegativeInteger(recolorGeneration) && typeof generation === "number" && typeof recolorGeneration === "number" && generation > recolorGeneration) {
26968
+ return [
26969
+ `${entryContext} recolor_generation ${generation} must not exceed recolor_generation ${recolorGeneration}.`
26970
+ ];
26971
+ }
26972
+ return [];
26973
+ }
26974
+ function validateMutations(mutations, issueNums, recolorGeneration, context) {
26975
+ if (!Array.isArray(mutations)) {
26976
+ return [`${context} mutations must be a list.`];
26977
+ }
26978
+ const errors = [];
26979
+ mutations.forEach((entry, position) => {
26980
+ const entryContext = `${context} mutations[${position}]`;
26981
+ if (!isObject14(entry)) {
26982
+ errors.push(`${entryContext} must be an object.`);
26983
+ return;
26984
+ }
26985
+ const op = entry["op"];
26986
+ if (!isEnumMember(VALID_MUTATION_OPS, op)) {
26987
+ errors.push(enumError(entryContext, "op", VALID_MUTATION_OPS, op));
26988
+ }
26989
+ errors.push(...validateMutationItemKey(entry, entryContext, op, issueNums));
26990
+ if (!isNonEmptyString2(entry["at"])) {
26991
+ errors.push(`${entryContext} at must be a non-empty string.`);
26992
+ }
26993
+ errors.push(
26994
+ ...validateMutationStateField(
26995
+ entry,
26996
+ entryContext,
26997
+ "prior_state",
26998
+ op,
26999
+ OPS_REQUIRING_NULL_PRIOR_STATE
27000
+ )
27001
+ );
27002
+ errors.push(
27003
+ ...validateMutationStateField(
27004
+ entry,
27005
+ entryContext,
27006
+ "new_state",
27007
+ op,
27008
+ OPS_REQUIRING_NULL_NEW_STATE
27009
+ )
27010
+ );
27011
+ errors.push(...validateMutationDisposition(entry, entryContext, op));
27012
+ errors.push(
27013
+ ...validateMutationGeneration(entry, entryContext, recolorGeneration)
27014
+ );
27015
+ });
27016
+ return errors;
27017
+ }
27018
+ function validateDriftEvents(events, issueNums, context) {
27019
+ if (!Array.isArray(events)) {
27020
+ return [`${context} drift_events must be a list.`];
27021
+ }
27022
+ const errors = [];
27023
+ events.forEach((entry, position) => {
27024
+ const entryContext = `${context} drift_events[${position}]`;
27025
+ if (!isObject14(entry)) {
27026
+ errors.push(`${entryContext} must be an object.`);
27027
+ return;
27028
+ }
27029
+ const itemKey = entry["item_key"];
27030
+ if (!resolves(itemKey, issueNums)) {
27031
+ errors.push(
27032
+ `${entryContext} item_key ${pythonRepr9(itemKey)} does not resolve to an items[].issue_num.`
27033
+ );
27034
+ }
27035
+ for (const field of ["declared", "observed"]) {
27036
+ if (!isStringList(entry[field])) {
27037
+ errors.push(
27038
+ `${entryContext} ${field} must be a list of non-empty strings.`
27039
+ );
27040
+ }
27041
+ }
27042
+ const escapedPaths = entry["escaped_paths"];
27043
+ if (!isStringList(escapedPaths) || !Array.isArray(escapedPaths) || escapedPaths.length === 0) {
27044
+ errors.push(
27045
+ `${entryContext} escaped_paths must be a non-empty list of non-empty strings.`
27046
+ );
27047
+ }
27048
+ if (!isNonEmptyString2(entry["at"])) {
27049
+ errors.push(`${entryContext} at must be a non-empty string.`);
27050
+ }
27051
+ const action = entry["action"];
27052
+ if (!isEnumMember(VALID_DRIFT_ACTIONS, action)) {
27053
+ errors.push(
27054
+ enumError(entryContext, "action", VALID_DRIFT_ACTIONS, action)
27055
+ );
27056
+ }
27057
+ });
27058
+ return errors;
27059
+ }
27060
+
27061
+ // ../../extensions/drm-copilot/src/lib/validate/parallel-state-structures.ts
27062
+ var COHORT_COVERAGE_EXEMPT_STATES = "withdrawn merged blocked".split(" ");
27063
+ var RECEIPT_ARRAY_KEYS = "delegation_receipts skill_receipts mcp_call_receipts".split(" ");
27064
+ function collectItemKeysAndStates(items) {
27065
+ const pairs = [];
27066
+ if (!Array.isArray(items)) {
27067
+ return pairs;
27068
+ }
27069
+ for (const entry of items) {
27070
+ if (!isObject14(entry)) {
27071
+ continue;
27072
+ }
27073
+ const issueNum = entry["issue_num"];
27074
+ if (typeof issueNum === "number" && Number.isInteger(issueNum) && issueNum > 0) {
27075
+ pairs.push({ issueNum, state: entry["state"] });
27076
+ }
27077
+ }
27078
+ return pairs;
27079
+ }
27080
+ function collectIssueNumbers(items) {
27081
+ return new Set(collectItemKeysAndStates(items).map((pair) => pair.issueNum));
27082
+ }
27083
+ function validateCohortEntry(entry, entryContext, issueNums, recolorGeneration) {
27084
+ const errors = [];
27085
+ const index = entry["index"];
27086
+ if (!isNonNegativeInteger(index)) {
27087
+ errors.push(
27088
+ `${entryContext} index must be a non-negative integer; found: ${pythonRepr9(index)}.`
27089
+ );
27090
+ }
27091
+ const generation = entry["generation"];
27092
+ if (!isNonNegativeInteger(generation)) {
27093
+ errors.push(
27094
+ `${entryContext} generation must be a non-negative integer; found: ${pythonRepr9(generation)}.`
27095
+ );
27096
+ } else if (recolorGeneration !== null && typeof generation === "number" && generation > recolorGeneration) {
27097
+ errors.push(
27098
+ `${entryContext} generation ${generation} must not exceed recolor_generation ${recolorGeneration}.`
27099
+ );
27100
+ }
27101
+ const itemKeys = entry["item_keys"];
27102
+ if (!Array.isArray(itemKeys)) {
27103
+ errors.push(`${entryContext} item_keys must be a list.`);
27104
+ return errors;
27105
+ }
27106
+ for (const key of itemKeys) {
27107
+ if (typeof key !== "number" || !Number.isInteger(key) || !issueNums.has(key)) {
27108
+ errors.push(
27109
+ `${entryContext} item_keys entry ${pythonRepr9(key)} does not resolve to an items[].issue_num.`
27110
+ );
27111
+ }
27112
+ }
27113
+ return errors;
27114
+ }
27115
+ function validateCohortShapes(cohorts, issueNums, recolorGeneration, context) {
27116
+ const errors = [];
27117
+ const generationOk = isNonNegativeInteger(recolorGeneration);
27118
+ if (!generationOk) {
27119
+ errors.push(
27120
+ `${context} recolor_generation must be a non-negative integer; found: ${pythonRepr9(recolorGeneration)}.`
27121
+ );
27122
+ }
27123
+ if (!Array.isArray(cohorts)) {
27124
+ errors.push(`${context} cohorts must be a list.`);
27125
+ return errors;
27126
+ }
27127
+ const bound = generationOk && typeof recolorGeneration === "number" ? recolorGeneration : null;
27128
+ cohorts.forEach((entry, position) => {
27129
+ const entryContext = `${context} cohorts[${position}]`;
27130
+ if (!isObject14(entry)) {
27131
+ errors.push(`${entryContext} must be an object.`);
27132
+ return;
27133
+ }
27134
+ errors.push(...validateCohortEntry(entry, entryContext, issueNums, bound));
27135
+ });
27136
+ return errors;
27137
+ }
27138
+ function currentGenerationCohorts(cohorts, recolorGeneration) {
27139
+ if (!isNonNegativeInteger(recolorGeneration) || !Array.isArray(cohorts)) {
27140
+ return [];
27141
+ }
27142
+ return cohorts.filter(isObject14).filter((entry) => entry["generation"] === recolorGeneration);
27143
+ }
27144
+ function validateCurrentGenerationCohorts(cohorts, items, recolorGeneration, context) {
27145
+ const current = currentGenerationCohorts(cohorts, recolorGeneration);
27146
+ const errors = [];
27147
+ const seenIndices = /* @__PURE__ */ new Set();
27148
+ const duplicateIndices = /* @__PURE__ */ new Set();
27149
+ const membershipCounts = /* @__PURE__ */ new Map();
27150
+ for (const entry of current) {
27151
+ const index = entry["index"];
27152
+ if (isNonNegativeInteger(index) && typeof index === "number") {
27153
+ if (seenIndices.has(index)) {
27154
+ duplicateIndices.add(index);
27155
+ }
27156
+ seenIndices.add(index);
27157
+ }
27158
+ const itemKeys = entry["item_keys"];
27159
+ if (!Array.isArray(itemKeys)) {
27160
+ continue;
27161
+ }
27162
+ for (const key of itemKeys) {
27163
+ if (typeof key === "number" && Number.isInteger(key)) {
27164
+ membershipCounts.set(key, (membershipCounts.get(key) ?? 0) + 1);
27165
+ }
27166
+ }
27167
+ }
27168
+ for (const index of [...duplicateIndices].sort(
27169
+ (left, right) => left - right
27170
+ )) {
27171
+ errors.push(
27172
+ `${context} has duplicate current-generation cohorts[].index: ${index}.`
27173
+ );
27174
+ }
27175
+ const pairs = [...collectItemKeysAndStates(items)].sort(
27176
+ (left, right) => left.issueNum - right.issueNum
27177
+ );
27178
+ for (const { issueNum, state } of pairs) {
27179
+ const count = membershipCounts.get(issueNum) ?? 0;
27180
+ if (count === 1) {
27181
+ continue;
27182
+ }
27183
+ if (count === 0 && isEnumMember(COHORT_COVERAGE_EXEMPT_STATES, state)) {
27184
+ continue;
27185
+ }
27186
+ errors.push(
27187
+ `${context} item ${issueNum} in state ${pythonRepr9(state)} must appear in exactly one current-generation cohort; found ${count}.`
27188
+ );
27189
+ }
27190
+ return errors;
27191
+ }
27192
+ function validateCurrentCohortBound(currentCohort, cohorts, recolorGeneration, context) {
27193
+ if (!isNonNegativeInteger(currentCohort) || typeof currentCohort !== "number") {
27194
+ return [
27195
+ `${context} current_cohort must be a non-negative integer; found: ${pythonRepr9(currentCohort)}.`
27196
+ ];
27197
+ }
27198
+ const indices = [];
27199
+ for (const entry of currentGenerationCohorts(cohorts, recolorGeneration)) {
27200
+ const index = entry["index"];
27201
+ if (isNonNegativeInteger(index) && typeof index === "number") {
27202
+ indices.push(index);
27203
+ }
27204
+ }
27205
+ if (indices.length === 0) {
27206
+ return [];
27207
+ }
27208
+ const highest = Math.max(...indices);
27209
+ if (currentCohort > highest) {
27210
+ return [
27211
+ `${context} current_cohort ${currentCohort} must not exceed the maximum current-generation cohorts[].index ${highest}.`
27212
+ ];
27213
+ }
27214
+ return [];
27215
+ }
27216
+ function validateEdgeEndpoints(entry, entryContext, issueNums) {
27217
+ const errors = [];
27218
+ const endpoints = /* @__PURE__ */ new Map();
27219
+ for (const field of ["a", "b"]) {
27220
+ const value = entry[field];
27221
+ if (typeof value === "number" && Number.isInteger(value) && issueNums.has(value)) {
27222
+ endpoints.set(field, value);
27223
+ } else {
27224
+ errors.push(
27225
+ `${entryContext} ${field} ${pythonRepr9(value)} does not resolve to an items[].issue_num.`
27226
+ );
27227
+ }
27228
+ }
27229
+ if (endpoints.size !== 2) {
27230
+ return { errors, pair: null };
27231
+ }
27232
+ const first = endpoints.get("a") ?? 0;
27233
+ const second = endpoints.get("b") ?? 0;
27234
+ if (first === second) {
27235
+ errors.push(`${entryContext} endpoints must be distinct; found: ${first}.`);
27236
+ return { errors, pair: null };
27237
+ }
27238
+ if (first > second) {
27239
+ errors.push(
27240
+ `${entryContext} must be normalized with a < b; found: (${first}, ${second}).`
27241
+ );
27242
+ return { errors, pair: null };
27243
+ }
27244
+ return { errors, pair: [first, second] };
27245
+ }
27246
+ function validateConflictEdges(edges, issueNums, context) {
27247
+ if (!Array.isArray(edges)) {
27248
+ return [`${context} conflict_edges must be a list.`];
27249
+ }
27250
+ const errors = [];
27251
+ const seen = /* @__PURE__ */ new Set();
27252
+ const duplicates = /* @__PURE__ */ new Map();
27253
+ edges.forEach((entry, position) => {
27254
+ const entryContext = `${context} conflict_edges[${position}]`;
27255
+ if (!isObject14(entry)) {
27256
+ errors.push(`${entryContext} must be an object.`);
27257
+ return;
27258
+ }
27259
+ const { errors: endpointErrors, pair } = validateEdgeEndpoints(
27260
+ entry,
27261
+ entryContext,
27262
+ issueNums
27263
+ );
27264
+ errors.push(...endpointErrors);
27265
+ const reason = entry["reason"];
27266
+ if (!isEnumMember(VALID_EDGE_REASONS, reason)) {
27267
+ errors.push(
27268
+ enumError(entryContext, "reason", VALID_EDGE_REASONS, reason)
27269
+ );
27270
+ }
27271
+ if (pair === null) {
27272
+ return;
27273
+ }
27274
+ const key = `${pair[0]},${pair[1]}`;
27275
+ if (seen.has(key)) {
27276
+ duplicates.set(key, pair);
27277
+ }
27278
+ seen.add(key);
27279
+ });
27280
+ const ordered = [...duplicates.values()].sort(
27281
+ (left, right) => left[0] - right[0] || left[1] - right[1]
27282
+ );
27283
+ for (const pair of ordered) {
27284
+ errors.push(
27285
+ `${context} has duplicate conflict_edges[] pair: (${pair[0]}, ${pair[1]}).`
27286
+ );
27287
+ }
27288
+ return errors;
27289
+ }
27290
+ function validateReceiptArrays(state, context) {
27291
+ const errors = [];
27292
+ for (const key of RECEIPT_ARRAY_KEYS) {
27293
+ if (key in state && !Array.isArray(state[key])) {
27294
+ errors.push(`${context} ${key} must be a list when present.`);
27295
+ }
27296
+ }
27297
+ return errors;
27298
+ }
27299
+
27300
+ // ../../extensions/drm-copilot/src/lib/validate/parallel-orchestrator-state-core.ts
27301
+ var CONTEXT = "Parallel checkpoint";
27302
+ var EXPECTED_ROUTE_ID2 = "parallel";
27303
+ var MIN_CONCURRENCY = 1;
27304
+ var MAX_CONCURRENCY = 8;
27305
+ var REQUIRED_KEYS4 = [
27306
+ "objective",
27307
+ "completed_steps",
27308
+ "next_step",
27309
+ "last_updated",
27310
+ "route_id",
27311
+ "parallel_slug",
27312
+ "parallel_manifest_path",
27313
+ "parallel_status_doc_path",
27314
+ "mode",
27315
+ "max_concurrency",
27316
+ "current_cohort",
27317
+ "recolor_generation",
27318
+ "cohorts",
27319
+ "items",
27320
+ "conflict_edges",
27321
+ "mutations",
27322
+ "drift_events"
27323
+ ];
27324
+ function missingRequiredKeys(state) {
27325
+ return REQUIRED_KEYS4.filter((key) => !(key in state)).map(
27326
+ (key) => `${CONTEXT} missing required key: ${key}.`
27327
+ );
27328
+ }
27329
+ function validateIdentity(state) {
27330
+ const errors = [];
27331
+ const routeId = state["route_id"];
27332
+ if ("route_id" in state && routeId !== EXPECTED_ROUTE_ID2) {
27333
+ errors.push(
27334
+ `${CONTEXT} route_id must be '${EXPECTED_ROUTE_ID2}'; found: ${pythonRepr9(routeId)}.`
27335
+ );
27336
+ }
27337
+ const mode = state["mode"];
27338
+ if ("mode" in state && !isEnumMember(VALID_MODES, mode)) {
27339
+ errors.push(enumError(CONTEXT, "mode", VALID_MODES, mode));
27340
+ }
27341
+ const concurrency = state["max_concurrency"];
27342
+ if ("max_concurrency" in state && !inBoundedRange(concurrency, MIN_CONCURRENCY, MAX_CONCURRENCY)) {
27343
+ errors.push(
27344
+ `${CONTEXT} max_concurrency must be an integer from ${MIN_CONCURRENCY} through ${MAX_CONCURRENCY}; found: ${pythonRepr9(concurrency)}.`
27345
+ );
27346
+ }
27347
+ return errors;
27348
+ }
27349
+ function validateCollections(state) {
27350
+ const items = state["items"];
27351
+ const issueNums = collectIssueNumbers(items);
27352
+ const generation = state["recolor_generation"];
27353
+ const cohorts = state["cohorts"];
27354
+ const errors = [];
27355
+ if ("items" in state) {
27356
+ errors.push(...validateItems(items, CONTEXT));
27357
+ }
27358
+ if ("cohorts" in state) {
27359
+ errors.push(
27360
+ ...validateCohortShapes(cohorts, issueNums, generation, CONTEXT)
27361
+ );
27362
+ errors.push(
27363
+ ...validateCurrentGenerationCohorts(cohorts, items, generation, CONTEXT)
27364
+ );
27365
+ }
27366
+ if ("current_cohort" in state) {
27367
+ errors.push(
27368
+ ...validateCurrentCohortBound(
27369
+ state["current_cohort"],
27370
+ cohorts,
27371
+ generation,
27372
+ CONTEXT
27373
+ )
27374
+ );
27375
+ }
27376
+ if ("conflict_edges" in state) {
27377
+ errors.push(
27378
+ ...validateConflictEdges(state["conflict_edges"], issueNums, CONTEXT)
27379
+ );
27380
+ }
27381
+ if ("mutations" in state) {
27382
+ errors.push(
27383
+ ...validateMutations(state["mutations"], issueNums, generation, CONTEXT)
27384
+ );
27385
+ }
27386
+ if ("drift_events" in state) {
27387
+ errors.push(
27388
+ ...validateDriftEvents(state["drift_events"], issueNums, CONTEXT)
27389
+ );
27390
+ }
27391
+ errors.push(...validateReceiptArrays(state, CONTEXT));
27392
+ return errors;
27393
+ }
27394
+ function recordsCloseMutation(state) {
27395
+ const mutations = state["mutations"];
27396
+ if (!Array.isArray(mutations)) {
27397
+ return false;
27398
+ }
27399
+ return mutations.some(
27400
+ (entry) => isObject14(entry) && entry["op"] === "close"
27401
+ );
27402
+ }
27403
+ function validateCompletion2(state) {
27404
+ const errors = [];
27405
+ const items = state["items"];
27406
+ const entries = Array.isArray(items) ? items : [];
27407
+ entries.forEach((entry, index) => {
27408
+ if (!isObject14(entry)) {
27409
+ return;
27410
+ }
27411
+ if (entry["state"] === "withdrawn") {
27412
+ return;
27413
+ }
27414
+ const mergeStatus = entry["merge_status"];
27415
+ if (!isEnumMember(MERGED_MERGE_STATUSES, mergeStatus)) {
27416
+ errors.push(
27417
+ `${itemContext(CONTEXT, index)} completion validation failed: merge_status is not merged or worktree_removed; found: ${pythonRepr9(mergeStatus)}.`
27418
+ );
27419
+ }
27420
+ });
27421
+ if (state["mode"] === "open" && !recordsCloseMutation(state)) {
27422
+ errors.push(
27423
+ `${CONTEXT} completion validation failed: open mode requires a mutations[] entry with op 'close'.`
27424
+ );
27425
+ }
27426
+ return errors;
27427
+ }
27428
+ function validateParallelOrchestratorStateText(text, options = {}) {
27429
+ let state;
27430
+ try {
27431
+ state = JSON.parse(text);
27432
+ } catch (error2) {
27433
+ const detail = error2 instanceof Error ? error2.message : String(error2);
27434
+ return [`${CONTEXT} is not valid JSON: ${detail}.`];
27435
+ }
27436
+ if (!isObject14(state)) {
27437
+ return [`${CONTEXT} root must be a JSON object.`];
27438
+ }
27439
+ const errors = [];
27440
+ errors.push(...missingRequiredKeys(state));
27441
+ errors.push(...validateIdentity(state));
27442
+ errors.push(...scanProhibitedKeys(state, CONTEXT));
27443
+ errors.push(...validateCollections(state));
27444
+ errors.push(...validateCohortBarrierOrdering(state));
27445
+ if (options.requireComplete === true) {
27446
+ errors.push(...validateCompletion2(state));
27447
+ }
27448
+ return errors;
27449
+ }
27450
+
27451
+ // ../../extensions/drm-copilot/src/lib/validate/parallel-planner-state-core.ts
27452
+ var CONTEXT2 = "Parallel planner checkpoint";
27453
+ var MIN_CONCURRENCY2 = 1;
27454
+ var MAX_CONCURRENCY2 = 8;
27455
+ var REQUIRED_KEYS5 = [
27456
+ "objective",
27457
+ "parallel_slug",
27458
+ "parallel_manifest_path",
27459
+ "mode",
27460
+ "max_concurrency",
27461
+ "items",
27462
+ "cohorts",
27463
+ "conflict_edges",
27464
+ "recolor_generation",
27465
+ "completed_steps",
27466
+ "next_step",
27467
+ "last_updated"
27468
+ ];
27469
+ var REQUIRED_ITEM_KEYS = [
27470
+ "issue_num",
27471
+ "feature_folder",
27472
+ "kind",
27473
+ "state",
27474
+ "blast_radius",
27475
+ "preparation_status",
27476
+ "research_path",
27477
+ "plan_path",
27478
+ "preflight_status"
27479
+ ];
27480
+ var VALID_COMPLEXITY_BANDS = [
27481
+ "C1",
27482
+ "C2",
27483
+ "C3",
27484
+ "C4"
27485
+ ];
27486
+ var READY_NEXT_STEP2 = "PARALLEL_EXECUTION_READY";
27487
+ var READY_PREPARATION_STATUS = "prepared";
27488
+ var READY_PREFLIGHT_STATUS = "PREFLIGHT: ALL CLEAR";
27489
+ var READY_RADIUS_SOURCE = "declared";
27490
+ var MINIMUM_READY_ITEMS = 2;
27491
+ var READY_ITEM_PATH_KEYS = ["research_path", "plan_path"];
27492
+ function kickoffPathFor(slug) {
27493
+ return `artifacts/orchestration/parallel-kickoff-${pythonStr2(slug)}.md`;
27494
+ }
27495
+ function missingRequiredKeys2(state) {
27496
+ return REQUIRED_KEYS5.filter((key) => !(key in state)).map(
27497
+ (key) => `${CONTEXT2} missing required key: ${key}.`
27498
+ );
27499
+ }
27500
+ function validateIdentity2(state) {
27501
+ const errors = [];
27502
+ for (const key of ["parallel_slug", "parallel_manifest_path"]) {
27503
+ if (key in state && !isNonEmptyString2(state[key])) {
27504
+ errors.push(`${CONTEXT2} ${key} must be a non-empty string.`);
27505
+ }
27506
+ }
27507
+ const mode = state["mode"];
27508
+ if ("mode" in state && !isEnumMember(VALID_MODES, mode)) {
27509
+ errors.push(enumError(CONTEXT2, "mode", VALID_MODES, mode));
27510
+ }
27511
+ const concurrency = state["max_concurrency"];
27512
+ if ("max_concurrency" in state && !inBoundedRange(concurrency, MIN_CONCURRENCY2, MAX_CONCURRENCY2)) {
27513
+ errors.push(
27514
+ `${CONTEXT2} max_concurrency must be an integer from ${MIN_CONCURRENCY2} through ${MAX_CONCURRENCY2}; found: ${pythonRepr9(concurrency)}.`
27515
+ );
27516
+ }
27517
+ return errors;
27518
+ }
27519
+ function itemRecords(items) {
27520
+ if (!Array.isArray(items)) {
27521
+ return [];
27522
+ }
27523
+ const records = [];
27524
+ items.forEach((entry, index) => {
27525
+ if (isObject14(entry)) {
27526
+ records.push({ index, record: entry });
27527
+ }
27528
+ });
27529
+ return records;
27530
+ }
27531
+ function validateItemContract(items) {
27532
+ const errors = [];
27533
+ for (const { index, record: record2 } of itemRecords(items)) {
27534
+ const entryContext = itemContext(CONTEXT2, index);
27535
+ for (const key of REQUIRED_ITEM_KEYS) {
27536
+ if (!(key in record2)) {
27537
+ errors.push(`${entryContext} missing required key: ${key}.`);
27538
+ }
27539
+ }
27540
+ const band = record2["complexity_band"];
27541
+ if ("complexity_band" in record2 && !isEnumMember(VALID_COMPLEXITY_BANDS, band)) {
27542
+ errors.push(
27543
+ enumError(
27544
+ entryContext,
27545
+ "complexity_band",
27546
+ VALID_COMPLEXITY_BANDS,
27547
+ band
27548
+ )
27549
+ );
27550
+ }
27551
+ }
27552
+ return errors;
27553
+ }
27554
+ function validateCollections2(state) {
27555
+ const items = state["items"];
27556
+ const issueNums = collectIssueNumbers(items);
27557
+ const generation = state["recolor_generation"];
27558
+ const cohorts = state["cohorts"];
27559
+ const errors = [];
27560
+ if ("items" in state) {
27561
+ errors.push(...validateItems(items, CONTEXT2, true));
27562
+ errors.push(...validateItemContract(items));
27563
+ }
27564
+ if ("cohorts" in state) {
27565
+ errors.push(
27566
+ ...validateCohortShapes(cohorts, issueNums, generation, CONTEXT2)
27567
+ );
27568
+ errors.push(
27569
+ ...validateCurrentGenerationCohorts(cohorts, items, generation, CONTEXT2)
27570
+ );
27571
+ }
27572
+ if ("current_cohort" in state) {
27573
+ errors.push(
27574
+ ...validateCurrentCohortBound(
27575
+ state["current_cohort"],
27576
+ cohorts,
27577
+ generation,
27578
+ CONTEXT2
27579
+ )
27580
+ );
27581
+ }
27582
+ if ("conflict_edges" in state) {
27583
+ errors.push(
27584
+ ...validateConflictEdges(state["conflict_edges"], issueNums, CONTEXT2)
27585
+ );
27586
+ }
27587
+ return errors;
27588
+ }
27589
+ function validateReadyItem(record2, entryContext) {
27590
+ const errors = [];
27591
+ const preparationStatus = record2["preparation_status"];
27592
+ if (preparationStatus !== READY_PREPARATION_STATUS) {
27593
+ errors.push(
27594
+ `${entryContext} preparation_status must be ${pythonRepr9(READY_PREPARATION_STATUS)}; found: ${pythonRepr9(preparationStatus)}.`
27595
+ );
27596
+ }
27597
+ const preflightStatus = record2["preflight_status"];
27598
+ if (preflightStatus !== READY_PREFLIGHT_STATUS) {
27599
+ errors.push(
27600
+ `${entryContext} preflight_status must be ${pythonRepr9(READY_PREFLIGHT_STATUS)}; found: ${pythonRepr9(preflightStatus)}.`
27601
+ );
27602
+ }
27603
+ for (const key of READY_ITEM_PATH_KEYS) {
27604
+ if (!isNonEmptyString2(record2[key])) {
27605
+ errors.push(`${entryContext} ${key} must be a non-empty string.`);
27606
+ }
27607
+ }
27608
+ const radius = record2["blast_radius"];
27609
+ const source = isObject14(radius) ? radius["source"] : null;
27610
+ if (source !== READY_RADIUS_SOURCE) {
27611
+ errors.push(
27612
+ `${entryContext} blast_radius.source must be ${pythonRepr9(READY_RADIUS_SOURCE)} for execution readiness; found: ${pythonRepr9(source)}.`
27613
+ );
27614
+ }
27615
+ return errors;
27616
+ }
27617
+ function validateReadyGate(state) {
27618
+ const errors = [];
27619
+ const items = state["items"];
27620
+ if (Array.isArray(items)) {
27621
+ const count = items.length;
27622
+ if (count < MINIMUM_READY_ITEMS) {
27623
+ errors.push(
27624
+ `${CONTEXT2} requires at least ${MINIMUM_READY_ITEMS} items for execution readiness; found: ${count}.`
27625
+ );
27626
+ }
27627
+ for (const { index, record: record2 } of itemRecords(items)) {
27628
+ errors.push(...validateReadyItem(record2, itemContext(CONTEXT2, index)));
27629
+ }
27630
+ }
27631
+ const nextStep = state["next_step"];
27632
+ if (nextStep !== READY_NEXT_STEP2) {
27633
+ errors.push(
27634
+ `${CONTEXT2} next_step must be ${pythonRepr9(READY_NEXT_STEP2)}; found: ${pythonRepr9(nextStep)}.`
27635
+ );
27636
+ }
27637
+ const expectedKickoff = kickoffPathFor(state["parallel_slug"]);
27638
+ const kickoffPromptPath = state["kickoff_prompt_path"];
27639
+ if (kickoffPromptPath !== expectedKickoff) {
27640
+ errors.push(
27641
+ `${CONTEXT2} kickoff_prompt_path must be ${pythonRepr9(expectedKickoff)}; found: ${pythonRepr9(kickoffPromptPath)}.`
27642
+ );
27643
+ }
27644
+ return errors;
27645
+ }
27646
+ function validateParallelPlannerStateText(text, options = {}) {
27647
+ let state;
27648
+ try {
27649
+ state = JSON.parse(text);
27650
+ } catch (error2) {
27651
+ const detail = error2 instanceof Error ? error2.message : String(error2);
27652
+ return [`${CONTEXT2} is not valid JSON: ${detail}.`];
27653
+ }
27654
+ if (!isObject14(state)) {
27655
+ return [`${CONTEXT2} root must be a JSON object.`];
27656
+ }
27657
+ const errors = [];
27658
+ errors.push(...missingRequiredKeys2(state));
27659
+ errors.push(...validateIdentity2(state));
27660
+ errors.push(...scanProhibitedKeys(state, CONTEXT2));
27661
+ errors.push(...validateCollections2(state));
27662
+ if (options.requireReadyForExecution === true) {
27663
+ errors.push(...validateReadyGate(state));
27664
+ }
27665
+ return errors;
27666
+ }
27667
+
27668
+ // ../../extensions/drm-copilot/src/lib/validate/policy-audit-artifact.ts
27669
+ var COVERAGE_PERCENT_RE = /\b\d+(?:\.\d+)?%/;
27670
+ var POLICY_AUDIT_REQUIRED_HEADINGS = [
27671
+ "## Executive Summary",
27672
+ "## 1. General Unit Test Policy Compliance",
27673
+ "## 2. General Code Change Policy Compliance",
27674
+ "## 3. Language-Specific Code Change Policy Compliance",
27675
+ "## 4. Language-Specific Unit Test Policy Compliance",
27676
+ "## 5. Test Coverage Detail",
27677
+ "## 6. Test Execution Metrics",
27678
+ "## 7. Code Quality Checks",
27679
+ "## 8. Gaps and Exceptions",
27680
+ "## 9. Summary of Changes",
27681
+ "## 10. Compliance Verdict",
27682
+ "## Appendix A: Test Inventory",
27683
+ "## Appendix B: Toolchain Commands Reference"
27684
+ ];
27685
+ var POLICY_AUDIT_REQUIRED_CHECKLIST_LABELS = [
27686
+ "TypeScript baseline coverage artifact:",
27687
+ "TypeScript post-change coverage artifact:",
27688
+ "PowerShell baseline coverage artifact:",
27689
+ "PowerShell post-change coverage artifact:",
27690
+ "Per-language comparison summary:"
27691
+ ];
27692
+ var POLICY_AUDIT_COMPARISON_HEADING = "### 1.2.1 Per-Language Coverage Comparison";
27693
+ var PLACEHOLDER_MARKERS = [
27694
+ "[n]",
27695
+ "[path",
27696
+ "[artifact",
27697
+ "[section reference",
27698
+ "[language]",
27699
+ "tbd",
27700
+ "unverified",
27701
+ "missing"
27702
+ ];
27703
+ var TEMPLATE_RESOLVER_TOOL = "resolve_policy_audit_template_asset";
27704
+ var TEMPLATE_RESOLVER_MISSING_MARKERS = [
27705
+ "not exposed",
27706
+ "was not exposed",
27707
+ "missing resolver exposure",
27708
+ "fallback template",
27709
+ "fallback-template"
27710
+ ];
27711
+ function hasNumericCoverage(value) {
27712
+ return COVERAGE_PERCENT_RE.test(value);
27713
+ }
27714
+ function isNaValue(value) {
27715
+ return value.trim().toLowerCase().startsWith("n/a");
27716
+ }
27717
+ function hasPlaceholderMarker(value) {
27718
+ const lowered = value.toLowerCase();
27719
+ return PLACEHOLDER_MARKERS.some((marker) => lowered.includes(marker));
27720
+ }
27721
+ function reportsMissingTemplateResolverSuccess(text) {
27722
+ const lowered = text.toLowerCase();
27723
+ if (!lowered.includes(TEMPLATE_RESOLVER_TOOL)) {
27724
+ return false;
27725
+ }
27726
+ if (!TEMPLATE_RESOLVER_MISSING_MARKERS.some((m) => lowered.includes(m))) {
27727
+ return false;
27728
+ }
27729
+ return /\b(pass|ready|readiness)\b/.test(lowered);
27730
+ }
27731
+ function extractPolicyAuditCoverageRows(text) {
27732
+ const rows = [];
27733
+ for (const line of text.split("\n")) {
27734
+ if (!line.startsWith("|")) {
27735
+ continue;
27736
+ }
27737
+ const segments = line.split("|");
27738
+ const cells = segments.slice(1, -1).map((cell) => cell.trim());
27739
+ if (cells.length !== 7) {
27740
+ continue;
27741
+ }
27742
+ const language = cells[0] ?? "";
27743
+ if (language === "Language" || language === "----------" || !language) {
27744
+ continue;
27745
+ }
27746
+ if (language.length > 0 && /^-+$/.test(language)) {
27747
+ continue;
27748
+ }
27749
+ rows.push({
27750
+ Language: language,
27751
+ "Files Changed": cells[1] ?? "",
27752
+ Tests: cells[2] ?? "",
27753
+ "Test Result": cells[3] ?? "",
27754
+ "Baseline Coverage": cells[4] ?? "",
27755
+ "Post-Change Coverage": cells[5] ?? "",
27756
+ "New Code Coverage": cells[6] ?? ""
27757
+ });
27758
+ }
27759
+ return rows;
27760
+ }
27761
+ function findPolicyAuditChecklistLine(text, label) {
27762
+ for (const line of text.split("\n")) {
27763
+ const stripped = line.trim();
27764
+ if (stripped.startsWith("- ") && stripped.includes(label)) {
27765
+ return stripped;
27766
+ }
27767
+ }
27768
+ return null;
27769
+ }
27770
+ function extractPolicyAuditComparisonLines(text) {
27771
+ let inSection = false;
27772
+ const comparisonLines = /* @__PURE__ */ new Map();
27773
+ for (const line of text.split("\n")) {
27774
+ const stripped = line.trim();
27775
+ if (stripped === POLICY_AUDIT_COMPARISON_HEADING) {
27776
+ inSection = true;
27777
+ continue;
27778
+ }
27779
+ if (inSection && stripped.startsWith("### ")) {
27780
+ break;
27781
+ }
27782
+ if (!inSection || !stripped.startsWith("- ")) {
26206
27783
  continue;
26207
27784
  }
26208
27785
  const body = stripped.slice(2);
@@ -26492,6 +28069,20 @@ function validateArtifact(input) {
26492
28069
  }
26493
28070
  case "epic-kickoff":
26494
28071
  return validateEpicKickoffText(input.text);
28072
+ case "parallel-orchestrator-state": {
28073
+ const options = {
28074
+ ...input.requireComplete === void 0 ? {} : { requireComplete: input.requireComplete }
28075
+ };
28076
+ return validateParallelOrchestratorStateText(input.text, options);
28077
+ }
28078
+ case "parallel-planner-state": {
28079
+ const options = {
28080
+ ...input.requireReadyForExecution === void 0 ? {} : { requireReadyForExecution: input.requireReadyForExecution }
28081
+ };
28082
+ return validateParallelPlannerStateText(input.text, options);
28083
+ }
28084
+ case "parallel-kickoff":
28085
+ return validateParallelKickoffText(input.text);
26495
28086
  default:
26496
28087
  return [`Unsupported artifact type: ${input.artifactType}`];
26497
28088
  }
@@ -28065,7 +29656,7 @@ function resolveReadinessSignal(fs9, featureDir) {
28065
29656
  }
28066
29657
  return [null, null];
28067
29658
  }
28068
- function relativeToPosix4(root, path11) {
29659
+ function relativeToPosix5(root, path11) {
28069
29660
  const normalizedRoot = toPosixPath2(root).replace(/\/+$/u, "");
28070
29661
  const normalized = toPosixPath2(path11);
28071
29662
  if (normalized.startsWith(`${normalizedRoot}/`)) {
@@ -28103,7 +29694,7 @@ function discoverCanonicalEvidenceFiles(fs9, root, feature) {
28103
29694
  for (const pattern of CANONICAL_GLOBS) {
28104
29695
  for (const candidate of fs9.glob(featureRoot, pattern)) {
28105
29696
  if (fs9.isFile(candidate)) {
28106
- discovered.add(relativeToPosix5(normalizedRoot, candidate));
29697
+ discovered.add(relativeToPosix6(normalizedRoot, candidate));
28107
29698
  }
28108
29699
  }
28109
29700
  }
@@ -28174,7 +29765,7 @@ function parseIntegerStrict(value) {
28174
29765
  }
28175
29766
  return Number.parseInt(value, 10);
28176
29767
  }
28177
- function relativeToPosix5(root, absolute) {
29768
+ function relativeToPosix6(root, absolute) {
28178
29769
  const normalized = toPosixPath2(absolute);
28179
29770
  if (normalized.startsWith(`${root}/`)) {
28180
29771
  return normalized.slice(root.length + 1);
@@ -28371,11 +29962,11 @@ function buildContextFiles(params) {
28371
29962
  const contextFiles = [];
28372
29963
  for (const path11 of candidatePaths) {
28373
29964
  if (fs9.exists(path11)) {
28374
- contextFiles.push(relativeToPosix4(root, path11));
29965
+ contextFiles.push(relativeToPosix5(root, path11));
28375
29966
  }
28376
29967
  }
28377
29968
  if (readinessSource !== null) {
28378
- contextFiles.push(relativeToPosix4(root, readinessSource));
29969
+ contextFiles.push(relativeToPosix5(root, readinessSource));
28379
29970
  }
28380
29971
  const evidenceContextFiles = discoverCanonicalEvidenceFiles(
28381
29972
  fs9,