@danmoisan/drm-copilot-mcp 1.1.17 → 1.1.18

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 (56) hide show
  1. package/out/mcp-server.js +500 -106
  2. package/package.json +4 -3
  3. package/resources/claude-customizations/.claude/agents/feature-review.md +10 -1
  4. package/resources/claude-customizations/.claude/agents/orchestrator.md +16 -3
  5. package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +6 -0
  6. package/resources/claude-customizations/.claude/lib/bash/parallel-lane-assertion.sh +4 -2
  7. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1 +6 -13
  8. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +375 -0
  9. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateReceipts.psm1 +22 -15
  10. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRemediationAccounting.psm1 +337 -0
  11. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingContract.psm1 +9 -1
  12. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +119 -3
  13. package/resources/claude-customizations/.claude/rules/quality-tiers.md +1 -1
  14. package/resources/claude-customizations/.claude/skills/acceptance-criteria-tracking/SKILL.md +8 -0
  15. package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +2 -0
  16. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +11 -3
  17. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup-worktrees.sh +11 -2
  18. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh +169 -5
  19. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_preserve_lib.sh +1 -1
  20. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_report_records_lib.sh +6 -43
  21. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +4 -15
  22. package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +13 -6
  23. package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +4 -0
  24. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +10 -0
  25. package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +3 -1
  26. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +30 -12
  27. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +18 -3
  28. package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +5 -1
  29. package/resources/claude-customizations/pack-manifests/core.json +2 -0
  30. package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +8 -0
  31. package/resources/codex-and-agents-customizations/.agents/skills/epic-orchestrate/SKILL.md +5 -3
  32. package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +4 -0
  33. package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
  34. package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +30 -6
  35. package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +3 -1
  36. package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +30 -7
  37. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +41 -2
  38. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +18 -3
  39. package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +1 -1
  40. package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +2 -0
  41. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c1.toml +1 -0
  42. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c2.toml +1 -0
  43. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3-elevated.toml +1 -0
  44. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c3.toml +1 -0
  45. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer-c4.toml +1 -0
  46. package/resources/codex-and-agents-customizations/.codex/agents/feature-reviewer.toml +1 -0
  47. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +1 -1
  48. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +1 -1
  49. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +1 -1
  50. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +1 -1
  51. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +1 -1
  52. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +1 -1
  53. package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
  54. package/resources/customizations/.github/skills/acceptance-criteria-tracking/SKILL.md +8 -0
  55. package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +4 -0
  56. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +4 -0
package/out/mcp-server.js CHANGED
@@ -4150,13 +4150,14 @@ var require_fast_uri = __commonJS({
4150
4150
  if (!malformedIPLiteral) {
4151
4151
  malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
4152
4152
  }
4153
- if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
4154
- if (uri.indexOf("%") !== -1) {
4155
- if (parsed.host !== void 0 && !malformedIPLiteral) {
4156
- const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
4157
- parsed.host = reescapeHostDelimiters(host, isIP);
4158
- }
4153
+ if (uri.indexOf("%") !== -1 && parsed.host !== void 0 && !malformedIPLiteral) {
4154
+ let host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
4155
+ if (!isIP) {
4156
+ host = normalizePercentEncoding(host.toLowerCase());
4159
4157
  }
4158
+ parsed.host = reescapeHostDelimiters(host, isIP);
4159
+ }
4160
+ if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
4160
4161
  if (parsed.path) {
4161
4162
  parsed.path = normalizePathEncoding(parsed.path);
4162
4163
  }
@@ -9273,13 +9274,13 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
9273
9274
  }
9274
9275
  return propValues;
9275
9276
  });
9276
- const isObject15 = isObject;
9277
+ const isObject16 = isObject;
9277
9278
  const catchall = def.catchall;
9278
9279
  let value;
9279
9280
  inst._zod.parse = (payload, ctx) => {
9280
9281
  value ?? (value = _normalized.value);
9281
9282
  const input = payload.value;
9282
- if (!isObject15(input)) {
9283
+ if (!isObject16(input)) {
9283
9284
  payload.issues.push({
9284
9285
  expected: "object",
9285
9286
  code: "invalid_type",
@@ -9406,7 +9407,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
9406
9407
  return (payload, ctx) => fn(shape, payload, ctx);
9407
9408
  };
9408
9409
  let fastpass;
9409
- const isObject15 = isObject;
9410
+ const isObject16 = isObject;
9410
9411
  const jit = !globalConfig.jitless;
9411
9412
  const allowsEval2 = allowsEval;
9412
9413
  const fastEnabled = jit && allowsEval2.value;
@@ -9415,7 +9416,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
9415
9416
  inst._zod.parse = (payload, ctx) => {
9416
9417
  value ?? (value = _normalized.value);
9417
9418
  const input = payload.value;
9418
- if (!isObject15(input)) {
9419
+ if (!isObject16(input)) {
9419
9420
  payload.issues.push({
9420
9421
  expected: "object",
9421
9422
  code: "invalid_type",
@@ -25739,6 +25740,7 @@ var MERGED_STATUSES = /* @__PURE__ */ new Set([
25739
25740
  "merged",
25740
25741
  "worktree_removed"
25741
25742
  ]);
25743
+ var NOT_STARTED_MERGE_STATUS = "not_started";
25742
25744
  function isObject6(value) {
25743
25745
  return typeof value === "object" && value !== null && !Array.isArray(value);
25744
25746
  }
@@ -25819,6 +25821,9 @@ function validateMergeStatusEnum(features) {
25819
25821
  }
25820
25822
  return errors;
25821
25823
  }
25824
+ function hasStarted(feature) {
25825
+ return typeof feature["worktree_created_at"] === "string" || feature["merge_status"] !== NOT_STARTED_MERGE_STATUS;
25826
+ }
25822
25827
  function validateWaveBarrierOrdering(features) {
25823
25828
  const errors = [];
25824
25829
  const byFolder = /* @__PURE__ */ new Map();
@@ -25835,6 +25840,9 @@ function validateWaveBarrierOrdering(features) {
25835
25840
  if (typeof folder !== "string" || !Array.isArray(dependsOn)) {
25836
25841
  continue;
25837
25842
  }
25843
+ if (!hasStarted(feature)) {
25844
+ continue;
25845
+ }
25838
25846
  const worktreeCreatedAt = feature["worktree_created_at"];
25839
25847
  for (const dependency of dependsOn) {
25840
25848
  const resolved = resolveFeatureReference(dependency, index);
@@ -25846,9 +25854,13 @@ function validateWaveBarrierOrdering(features) {
25846
25854
  const depConfirmedAt = dependencyFeature["merge_confirmed_at"];
25847
25855
  const statusViolation = typeof depMergeStatus !== "string" || !MERGED_STATUSES.has(depMergeStatus);
25848
25856
  const timingViolation = typeof depConfirmedAt === "string" && typeof worktreeCreatedAt === "string" && depConfirmedAt > worktreeCreatedAt;
25849
- if (statusViolation || timingViolation) {
25857
+ if (statusViolation) {
25858
+ errors.push(
25859
+ `EPIC_WAVE_BARRIER_VIOLATION: ${folder} is treated as started while dependency ${String(dependency)} is not merged`
25860
+ );
25861
+ } else if (timingViolation) {
25850
25862
  errors.push(
25851
- `EPIC_WAVE_BARRIER_VIOLATION: ${folder} started before dependency ${String(dependency)} merged`
25863
+ `EPIC_WAVE_BARRIER_VIOLATION: ${folder} worktree_created_at precedes dependency ${String(dependency)} merge_confirmed_at`
25852
25864
  );
25853
25865
  }
25854
25866
  }
@@ -27194,6 +27206,201 @@ function validateEpicPlannerStateText(text2, options = {}) {
27194
27206
  return errors;
27195
27207
  }
27196
27208
 
27209
+ // ../../extensions/drm-copilot/src/lib/validate/orchestrator-state-blocked-reason.ts
27210
+ var MECHANICAL_BLOCKED_REASONS = /* @__PURE__ */ new Set([
27211
+ "spawn_agent_unavailable",
27212
+ "delegation_launch_failed",
27213
+ "delegate_no_receipt",
27214
+ "delegate_contract_incomplete",
27215
+ "validator_failed",
27216
+ "user_requested_stop"
27217
+ ]);
27218
+ var NON_MECHANICAL_BLOCKED_REASONS = /* @__PURE__ */ new Set([
27219
+ "premise_falsified",
27220
+ "external_dependency",
27221
+ "policy_hold",
27222
+ "awaiting_ci",
27223
+ "human_decision_required"
27224
+ ]);
27225
+ var VALID_BLOCKED_REASONS = /* @__PURE__ */ new Set([
27226
+ "none",
27227
+ ...MECHANICAL_BLOCKED_REASONS,
27228
+ ...NON_MECHANICAL_BLOCKED_REASONS
27229
+ ]);
27230
+
27231
+ // ../../extensions/drm-copilot/src/lib/validate/orchestrator-state-promotion-tools.ts
27232
+ var FEATURE_PROMOTION_ENTRY_TOOL = "new_potential_entry";
27233
+ var BUG_PROMOTION_ENTRY_TOOL = "new_potential_bug_entry";
27234
+ var BUG_PROMOTION_TYPE = "bug";
27235
+ var PROMOTION_TYPE_KEY = "promotion-type";
27236
+ function resolvePromotionEntryTools(requiredMcpTools, state) {
27237
+ if (state[PROMOTION_TYPE_KEY] !== BUG_PROMOTION_TYPE) {
27238
+ return [...requiredMcpTools];
27239
+ }
27240
+ return requiredMcpTools.map(
27241
+ (tool) => tool === FEATURE_PROMOTION_ENTRY_TOOL ? BUG_PROMOTION_ENTRY_TOOL : tool
27242
+ );
27243
+ }
27244
+
27245
+ // ../../extensions/drm-copilot/src/lib/validate/orchestrator-state-issue-adoption.ts
27246
+ var ISSUE_ADOPTION_KEY = "issue_adoption";
27247
+ var POTENTIAL_TO_ISSUE_TOOL = "potential_to_issue";
27248
+ var ORIGIN_VALUES = /* @__PURE__ */ new Set([
27249
+ "transferred",
27250
+ "filed_before_orchestration",
27251
+ "epic_decomposition"
27252
+ ]);
27253
+ var VERIFIED_VIA_VALUES = /* @__PURE__ */ new Set([
27254
+ "gh_issue_view",
27255
+ "gh_api_get",
27256
+ "github_mcp_issue_read"
27257
+ ]);
27258
+ var WAIVABLE_TOOLS = /* @__PURE__ */ new Set([
27259
+ POTENTIAL_TO_ISSUE_TOOL,
27260
+ FEATURE_PROMOTION_ENTRY_TOOL,
27261
+ BUG_PROMOTION_ENTRY_TOOL
27262
+ ]);
27263
+ var PROMOTION_ENTRY_TOOLS = /* @__PURE__ */ new Set([
27264
+ FEATURE_PROMOTION_ENTRY_TOOL,
27265
+ BUG_PROMOTION_ENTRY_TOOL
27266
+ ]);
27267
+ var POTENTIAL_RECORD_PREFIX = "docs/features/potential/";
27268
+ var POTENTIAL_RECORD_SUFFIX = ".md";
27269
+ var ISSUE_NUM_PATTERN = /^[1-9][0-9]*$/;
27270
+ var ERROR_NOT_OBJECT = "Checkpoint issue_adoption must be an object when present.";
27271
+ var ERROR_ISSUE_NUM_FORMAT = "Checkpoint issue_adoption.issue_num must be a string of decimal digits without a leading zero.";
27272
+ var ERROR_ISSUE_NUM_MISMATCH = "Checkpoint issue_adoption.issue_num must equal the checkpoint issue-num.";
27273
+ var ERROR_ISSUE_URL = "Checkpoint issue_adoption.issue_url must end with /issues/ followed by issue_num.";
27274
+ var ERROR_ORIGIN = "Checkpoint issue_adoption.origin must be one of transferred, filed_before_orchestration, epic_decomposition.";
27275
+ var ERROR_VERIFIED_VIA = "Checkpoint issue_adoption.verified_via must be one of gh_issue_view, gh_api_get, github_mcp_issue_read.";
27276
+ var ERROR_VERIFIED_AT = "Checkpoint issue_adoption.verified_at must be present.";
27277
+ var ERROR_EVIDENCE = "Checkpoint issue_adoption.evidence must be a non-empty string.";
27278
+ var ERROR_WAIVED_TOOLS_SHAPE = "Checkpoint issue_adoption.waived_tools must be a non-empty list of tool names.";
27279
+ var ERROR_WAIVED_TOOLS_INCLUDE = "Checkpoint issue_adoption.waived_tools must include potential_to_issue.";
27280
+ function isPlainObject3(value) {
27281
+ return typeof value === "object" && value !== null && !Array.isArray(value);
27282
+ }
27283
+ function isNonBlankString(value) {
27284
+ return typeof value === "string" && value.trim().length > 0;
27285
+ }
27286
+ function validIssueNum(value) {
27287
+ return typeof value === "string" && ISSUE_NUM_PATTERN.test(value) ? value : null;
27288
+ }
27289
+ function issueIdentityErrors(adoption, state) {
27290
+ const errors = [];
27291
+ const issueNum = validIssueNum(adoption["issue_num"]);
27292
+ if (issueNum === null) {
27293
+ errors.push(ERROR_ISSUE_NUM_FORMAT);
27294
+ } else {
27295
+ const checkpointIssueNum = state["issue-num"];
27296
+ if (typeof checkpointIssueNum === "string" && checkpointIssueNum !== issueNum) {
27297
+ errors.push(ERROR_ISSUE_NUM_MISMATCH);
27298
+ }
27299
+ }
27300
+ const issueUrl = adoption["issue_url"];
27301
+ if (issueNum === null || typeof issueUrl !== "string" || !issueUrl.endsWith(`/issues/${issueNum}`)) {
27302
+ errors.push(ERROR_ISSUE_URL);
27303
+ }
27304
+ return errors;
27305
+ }
27306
+ function provenanceErrors(adoption) {
27307
+ const errors = [];
27308
+ const origin = adoption["origin"];
27309
+ if (typeof origin !== "string" || !ORIGIN_VALUES.has(origin)) {
27310
+ errors.push(ERROR_ORIGIN);
27311
+ }
27312
+ const verifiedVia = adoption["verified_via"];
27313
+ if (typeof verifiedVia !== "string" || !VERIFIED_VIA_VALUES.has(verifiedVia)) {
27314
+ errors.push(ERROR_VERIFIED_VIA);
27315
+ }
27316
+ const verifiedAt = adoption["verified_at"];
27317
+ if (verifiedAt === void 0 || verifiedAt === null || typeof verifiedAt === "string" && verifiedAt.trim().length === 0) {
27318
+ errors.push(ERROR_VERIFIED_AT);
27319
+ }
27320
+ if (!isNonBlankString(adoption["evidence"])) {
27321
+ errors.push(ERROR_EVIDENCE);
27322
+ }
27323
+ return errors;
27324
+ }
27325
+ function waivedToolList(value) {
27326
+ if (!Array.isArray(value)) {
27327
+ return null;
27328
+ }
27329
+ const items = value;
27330
+ if (items.length === 0 || !items.every((item) => isNonBlankString(item))) {
27331
+ return null;
27332
+ }
27333
+ return items;
27334
+ }
27335
+ function waivedToolErrors(waived, options) {
27336
+ const errors = [];
27337
+ const seen = /* @__PURE__ */ new Set();
27338
+ for (const tool of waived) {
27339
+ if (seen.has(tool)) {
27340
+ errors.push(
27341
+ `Checkpoint issue_adoption.waived_tools lists a tool more than once: ${tool}.`
27342
+ );
27343
+ } else if (!WAIVABLE_TOOLS.has(tool)) {
27344
+ errors.push(
27345
+ `Checkpoint issue_adoption.waived_tools names a tool that cannot be waived: ${tool}.`
27346
+ );
27347
+ } else if (!options.requiredMcpTools.includes(tool)) {
27348
+ errors.push(
27349
+ `Checkpoint issue_adoption.waived_tools names a tool that is not required by route ${options.routeId}: ${tool}.`
27350
+ );
27351
+ } else if (options.successfulTools.has(tool)) {
27352
+ errors.push(
27353
+ `Checkpoint issue_adoption.waived_tools names a tool that has a successful MCP receipt: ${tool}.`
27354
+ );
27355
+ }
27356
+ seen.add(tool);
27357
+ }
27358
+ if (!seen.has(POTENTIAL_TO_ISSUE_TOOL)) {
27359
+ errors.push(ERROR_WAIVED_TOOLS_INCLUDE);
27360
+ }
27361
+ return errors;
27362
+ }
27363
+ function potentialRecordErrors(waived, potentialRecord) {
27364
+ if (typeof potentialRecord === "string" && potentialRecord.startsWith(POTENTIAL_RECORD_PREFIX) && potentialRecord.endsWith(POTENTIAL_RECORD_SUFFIX)) {
27365
+ return [];
27366
+ }
27367
+ const errors = [];
27368
+ const reported = /* @__PURE__ */ new Set();
27369
+ for (const tool of waived) {
27370
+ if (PROMOTION_ENTRY_TOOLS.has(tool) && !reported.has(tool)) {
27371
+ errors.push(
27372
+ `Checkpoint issue_adoption.potential_record must name a markdown file under docs/features/potential/ when waiving ${tool}.`
27373
+ );
27374
+ reported.add(tool);
27375
+ }
27376
+ }
27377
+ return errors;
27378
+ }
27379
+ function resolveIssueAdoption(state, options) {
27380
+ if (!Object.prototype.hasOwnProperty.call(state, ISSUE_ADOPTION_KEY)) {
27381
+ return { errors: [], waivedTools: /* @__PURE__ */ new Set() };
27382
+ }
27383
+ const adoption = state[ISSUE_ADOPTION_KEY];
27384
+ if (!isPlainObject3(adoption)) {
27385
+ return { errors: [ERROR_NOT_OBJECT], waivedTools: /* @__PURE__ */ new Set() };
27386
+ }
27387
+ const errors = [
27388
+ ...issueIdentityErrors(adoption, state),
27389
+ ...provenanceErrors(adoption)
27390
+ ];
27391
+ const waived = waivedToolList(adoption["waived_tools"]);
27392
+ if (waived === null) {
27393
+ errors.push(ERROR_WAIVED_TOOLS_SHAPE);
27394
+ return { errors, waivedTools: /* @__PURE__ */ new Set() };
27395
+ }
27396
+ errors.push(...waivedToolErrors(waived, options));
27397
+ errors.push(...potentialRecordErrors(waived, adoption["potential_record"]));
27398
+ if (errors.length > 0) {
27399
+ return { errors, waivedTools: /* @__PURE__ */ new Set() };
27400
+ }
27401
+ return { errors: [], waivedTools: new Set(waived) };
27402
+ }
27403
+
27197
27404
  // ../../extensions/drm-copilot/src/lib/validate/orchestrator-state-routing.ts
27198
27405
  var ROUTING_MATRIX_RELATIVE_PATH = "config/orchestration-routing.json";
27199
27406
  var MANDATORY_ROUTE_PHASES = {
@@ -27382,7 +27589,10 @@ function validateRoutingContract(state, options = {}) {
27382
27589
  const errors = [];
27383
27590
  const requiredAgents = routeList(rawRoute, "required_agents");
27384
27591
  const requiredSkills = routeList(rawRoute, "required_skills");
27385
- const requiredMcpTools = routeList(rawRoute, "required_mcp_tools");
27592
+ const requiredMcpTools = resolvePromotionEntryTools(
27593
+ routeList(rawRoute, "required_mcp_tools"),
27594
+ state
27595
+ );
27386
27596
  if (stateList(state, "required_agents", requiredAgents) === null) {
27387
27597
  errors.push(
27388
27598
  `Checkpoint required_agents must match routing matrix for route ${routeId}.`
@@ -27411,11 +27621,20 @@ function validateRoutingContract(state, options = {}) {
27411
27621
  }
27412
27622
  }
27413
27623
  const actualTools = mcpTools(state);
27624
+ const adoption = resolveIssueAdoption(state, {
27625
+ routeId,
27626
+ requiredMcpTools,
27627
+ successfulTools: actualTools
27628
+ });
27414
27629
  for (const tool of requiredMcpTools) {
27630
+ if (adoption.waivedTools.has(tool)) {
27631
+ continue;
27632
+ }
27415
27633
  if (!actualTools.has(tool)) {
27416
27634
  errors.push(`Checkpoint missing successful MCP receipt: ${tool}.`);
27417
27635
  }
27418
27636
  }
27637
+ errors.push(...adoption.errors);
27419
27638
  errors.push(...validateEmptyListField(state, "local_execution_overrides"));
27420
27639
  errors.push(...validateEmptyListField(state, "delegation_bypasses"));
27421
27640
  errors.push(...validateLifecycleOperations(state));
@@ -27561,14 +27780,137 @@ function validateHumanInteraction(humanInteraction) {
27561
27780
  return errors;
27562
27781
  }
27563
27782
 
27783
+ // ../../extensions/drm-copilot/src/lib/validate/orchestrator-state-remediation-accounting.ts
27784
+ var REVIEW_OUTCOMES_KEY = "review_outcomes";
27785
+ var REVIEW_VERDICTS = [
27786
+ "PASS",
27787
+ "REMEDIATION_REQUIRED",
27788
+ "HALT_NON_REMEDIABLE",
27789
+ "AWAITING_CI"
27790
+ ];
27791
+ var REMEDIABILITY_CLASSES = [
27792
+ "autonomous",
27793
+ "external_dependency",
27794
+ "policy_hold",
27795
+ "awaiting_ci",
27796
+ "human_decision_required"
27797
+ ];
27798
+ var HALT_CLASSES = /* @__PURE__ */ new Set([
27799
+ "external_dependency",
27800
+ "policy_hold",
27801
+ "human_decision_required"
27802
+ ]);
27803
+ var REMEDIABLE_CLASS = "autonomous";
27804
+ function isObject11(value) {
27805
+ return typeof value === "object" && value !== null && !Array.isArray(value);
27806
+ }
27807
+ function pythonRepr8(value) {
27808
+ if (value === null || value === void 0) {
27809
+ return "None";
27810
+ }
27811
+ if (value === true) {
27812
+ return "True";
27813
+ }
27814
+ if (value === false) {
27815
+ return "False";
27816
+ }
27817
+ return String(value);
27818
+ }
27819
+ function deriveReviewVerdict(remediabilities) {
27820
+ for (const value of remediabilities) {
27821
+ if (!REMEDIABILITY_CLASSES.includes(value)) {
27822
+ throw new RangeError(`invalid remediability: ${value}`);
27823
+ }
27824
+ }
27825
+ if (remediabilities.length === 0) {
27826
+ return "PASS";
27827
+ }
27828
+ if (remediabilities.includes(REMEDIABLE_CLASS)) {
27829
+ return "REMEDIATION_REQUIRED";
27830
+ }
27831
+ if (remediabilities.some((value) => HALT_CLASSES.has(value))) {
27832
+ return "HALT_NON_REMEDIABLE";
27833
+ }
27834
+ return "AWAITING_CI";
27835
+ }
27836
+ function validateReviewOutcome(index, outcome) {
27837
+ const errors = [];
27838
+ const prefix = `Checkpoint remediation review outcome #${index}`;
27839
+ const verdict = outcome["verdict"];
27840
+ if (typeof verdict !== "string" || !REVIEW_VERDICTS.includes(verdict)) {
27841
+ errors.push(
27842
+ `${prefix} verdict must be one of PASS, REMEDIATION_REQUIRED, HALT_NON_REMEDIABLE, AWAITING_CI; got: ${pythonRepr8(verdict)}`
27843
+ );
27844
+ }
27845
+ const classes = [];
27846
+ const findings = outcome["findings"];
27847
+ if (!Array.isArray(findings)) {
27848
+ errors.push(`${prefix} findings must be a list.`);
27849
+ } else {
27850
+ findings.forEach((finding, findingIndex) => {
27851
+ if (!isObject11(finding)) {
27852
+ errors.push(`${prefix} finding #${findingIndex} must be an object.`);
27853
+ return;
27854
+ }
27855
+ const remediability = finding["remediability"];
27856
+ if (typeof remediability !== "string" || !REMEDIABILITY_CLASSES.includes(remediability)) {
27857
+ errors.push(
27858
+ `${prefix} finding #${findingIndex} remediability must be one of autonomous, external_dependency, policy_hold, awaiting_ci, human_decision_required; got: ${pythonRepr8(remediability)}`
27859
+ );
27860
+ return;
27861
+ }
27862
+ classes.push(remediability);
27863
+ });
27864
+ }
27865
+ if (errors.length === 0) {
27866
+ const expected = deriveReviewVerdict(classes);
27867
+ if (verdict !== expected) {
27868
+ errors.push(
27869
+ `${prefix} verdict ${pythonRepr8(verdict)} does not match its findings (expected ${expected}).`
27870
+ );
27871
+ }
27872
+ }
27873
+ return errors;
27874
+ }
27875
+ function validateReviewOutcomes(loop) {
27876
+ if (!Object.prototype.hasOwnProperty.call(loop, REVIEW_OUTCOMES_KEY)) {
27877
+ return [];
27878
+ }
27879
+ const outcomes = loop[REVIEW_OUTCOMES_KEY];
27880
+ if (!Array.isArray(outcomes)) {
27881
+ return ["Checkpoint remediation_loop review_outcomes must be a list."];
27882
+ }
27883
+ const errors = [];
27884
+ outcomes.forEach((outcome, index) => {
27885
+ if (!isObject11(outcome)) {
27886
+ errors.push(
27887
+ `Checkpoint remediation review outcome #${index} must be an object.`
27888
+ );
27889
+ return;
27890
+ }
27891
+ errors.push(...validateReviewOutcome(index, outcome));
27892
+ });
27893
+ return errors;
27894
+ }
27895
+
27564
27896
  // ../../extensions/drm-copilot/src/lib/validate/orchestrator-state-remediation.ts
27565
27897
  var REMEDIATION_LOOP_KEY = "remediation_loop";
27566
27898
  var REMEDIATION_CYCLES_KEY = "cycles";
27567
27899
  var EXECUTION_STATUSES_REQUIRING_CLEAR_PREFLIGHT = /* @__PURE__ */ new Set(["in_progress", "complete", "failed"]);
27568
27900
  var PREFLIGHT_CLEARED_STATUS = "clear";
27569
- function isObject11(value) {
27901
+ var COMPLETED_ATTEMPTS_KEY = "completed_attempts";
27902
+ var CANDIDATE_APPLIED_KEY = "candidate_applied";
27903
+ var OPENED_BY_REVIEW_KEY = "opened_by_review";
27904
+ var COMPLETED_EXECUTION_STATUS = "complete";
27905
+ function isObject12(value) {
27570
27906
  return typeof value === "object" && value !== null && !Array.isArray(value);
27571
27907
  }
27908
+ function isStrictInteger(value) {
27909
+ return typeof value === "number" && Number.isInteger(value);
27910
+ }
27911
+ function hasKey(value, key) {
27912
+ return Object.prototype.hasOwnProperty.call(value, key);
27913
+ }
27572
27914
  function validateRemediationCycle(index, cycle) {
27573
27915
  const errors = [];
27574
27916
  const planPath = cycle["plan_path"];
@@ -27580,7 +27922,7 @@ function validateRemediationCycle(index, cycle) {
27580
27922
  const executionStatus = cycle["execution_status"];
27581
27923
  if (typeof executionStatus === "string" && EXECUTION_STATUSES_REQUIRING_CLEAR_PREFLIGHT.has(executionStatus)) {
27582
27924
  const preflight = cycle["preflight"];
27583
- const preflightStatus = isObject11(preflight) ? preflight["final_status"] : void 0;
27925
+ const preflightStatus = isObject12(preflight) ? preflight["final_status"] : void 0;
27584
27926
  if (preflightStatus !== PREFLIGHT_CLEARED_STATUS) {
27585
27927
  errors.push(
27586
27928
  `Checkpoint remediation cycle #${index} execution_status is ${executionStatus} but preflight.final_status is not 'clear'.`
@@ -27594,22 +27936,79 @@ function validateRemediationCycle(index, cycle) {
27594
27936
  }
27595
27937
  return errors;
27596
27938
  }
27939
+ function opensRemediationReview(openedByReview, outcomes) {
27940
+ if (!isStrictInteger(openedByReview) || !Array.isArray(outcomes)) {
27941
+ return false;
27942
+ }
27943
+ if (openedByReview < 0 || openedByReview >= outcomes.length) {
27944
+ return false;
27945
+ }
27946
+ const target = outcomes[openedByReview];
27947
+ return isObject12(target) && target["verdict"] === "REMEDIATION_REQUIRED";
27948
+ }
27949
+ function validateRemediationAccounting(loop, cycleList) {
27950
+ const errors = [];
27951
+ const outcomes = loop[REVIEW_OUTCOMES_KEY];
27952
+ let appliedCount = 0;
27953
+ (cycleList ?? []).forEach((cycle, index) => {
27954
+ if (!isObject12(cycle)) {
27955
+ return;
27956
+ }
27957
+ const prefix = `Checkpoint remediation cycle #${index}`;
27958
+ if (hasKey(cycle, CANDIDATE_APPLIED_KEY)) {
27959
+ const candidateApplied = cycle[CANDIDATE_APPLIED_KEY];
27960
+ if (typeof candidateApplied !== "boolean") {
27961
+ errors.push(`${prefix} candidate_applied must be a boolean.`);
27962
+ } else if (candidateApplied) {
27963
+ appliedCount += 1;
27964
+ if (cycle["execution_status"] !== COMPLETED_EXECUTION_STATUS) {
27965
+ errors.push(
27966
+ `${prefix} candidate_applied is true but execution_status is not 'complete'.`
27967
+ );
27968
+ }
27969
+ }
27970
+ }
27971
+ if (hasKey(cycle, OPENED_BY_REVIEW_KEY) && !opensRemediationReview(cycle[OPENED_BY_REVIEW_KEY], outcomes)) {
27972
+ errors.push(
27973
+ `${prefix} opened_by_review must reference a review outcome whose verdict is REMEDIATION_REQUIRED.`
27974
+ );
27975
+ }
27976
+ });
27977
+ if (hasKey(loop, COMPLETED_ATTEMPTS_KEY)) {
27978
+ const completedAttempts = loop[COMPLETED_ATTEMPTS_KEY];
27979
+ if (!isStrictInteger(completedAttempts) || completedAttempts < 0) {
27980
+ errors.push(
27981
+ "Checkpoint remediation_loop completed_attempts must be a non-negative integer."
27982
+ );
27983
+ } else if (completedAttempts !== appliedCount) {
27984
+ errors.push(
27985
+ `Checkpoint remediation_loop completed_attempts is ${completedAttempts} but ${appliedCount} cycles have candidate_applied true.`
27986
+ );
27987
+ }
27988
+ }
27989
+ return errors;
27990
+ }
27597
27991
  function validateRemediationLoop(remediationLoop) {
27598
27992
  const errors = [];
27599
- if (!isObject11(remediationLoop)) {
27993
+ if (!isObject12(remediationLoop)) {
27600
27994
  return errors;
27601
27995
  }
27602
27996
  const cycles = remediationLoop[REMEDIATION_CYCLES_KEY];
27603
- if (!Array.isArray(cycles)) {
27604
- return errors;
27997
+ let cycleList = null;
27998
+ if (Array.isArray(cycles)) {
27999
+ cycleList = cycles;
28000
+ cycles.forEach((cycle, index) => {
28001
+ if (!isObject12(cycle)) {
28002
+ errors.push(
28003
+ `Checkpoint remediation cycle #${index} must be an object.`
28004
+ );
28005
+ return;
28006
+ }
28007
+ errors.push(...validateRemediationCycle(index, cycle));
28008
+ });
27605
28009
  }
27606
- cycles.forEach((cycle, index) => {
27607
- if (!isObject11(cycle)) {
27608
- errors.push(`Checkpoint remediation cycle #${index} must be an object.`);
27609
- return;
27610
- }
27611
- errors.push(...validateRemediationCycle(index, cycle));
27612
- });
28010
+ errors.push(...validateReviewOutcomes(remediationLoop));
28011
+ errors.push(...validateRemediationAccounting(remediationLoop, cycleList));
27613
28012
  return errors;
27614
28013
  }
27615
28014
 
@@ -27623,7 +28022,7 @@ var OUT_OF_SCOPE_STEP_KEYS = [
27623
28022
  "step9_status",
27624
28023
  "step10_status"
27625
28024
  ];
27626
- function pythonRepr8(value) {
28025
+ function pythonRepr9(value) {
27627
28026
  if (value === void 0 || value === null) {
27628
28027
  return "None";
27629
28028
  }
@@ -27638,11 +28037,11 @@ function pythonRepr8(value) {
27638
28037
  return String(value);
27639
28038
  }
27640
28039
  if (Array.isArray(value)) {
27641
- return `[${value.map(pythonRepr8).join(", ")}]`;
28040
+ return `[${value.map(pythonRepr9).join(", ")}]`;
27642
28041
  }
27643
28042
  if (typeof value === "object") {
27644
28043
  const entries = Object.entries(value).map(
27645
- ([key, item]) => `${pythonRepr8(key)}: ${pythonRepr8(item)}`
28044
+ ([key, item]) => `${pythonRepr9(key)}: ${pythonRepr9(item)}`
27646
28045
  );
27647
28046
  return `{${entries.join(", ")}}`;
27648
28047
  }
@@ -27656,13 +28055,13 @@ function validatePreparationTerminalContract(state) {
27656
28055
  const errors = [];
27657
28056
  if (state["next_step"] !== EXPECTED_NEXT_STEP) {
27658
28057
  errors.push(
27659
- `Preparation checkpoint next_step must be ${pythonRepr8(EXPECTED_NEXT_STEP)}, found ${pythonRepr8(state["next_step"])}.`
28058
+ `Preparation checkpoint next_step must be ${pythonRepr9(EXPECTED_NEXT_STEP)}, found ${pythonRepr9(state["next_step"])}.`
27660
28059
  );
27661
28060
  }
27662
28061
  for (const key of OUT_OF_SCOPE_STEP_KEYS) {
27663
28062
  if (state[key] !== "not-applicable") {
27664
28063
  errors.push(
27665
- `Preparation checkpoint ${key} must be 'not-applicable', found ${pythonRepr8(state[key])}.`
28064
+ `Preparation checkpoint ${key} must be 'not-applicable', found ${pythonRepr9(state[key])}.`
27666
28065
  );
27667
28066
  }
27668
28067
  }
@@ -27678,18 +28077,18 @@ var DELEGATING_AGENTS = /* @__PURE__ */ new Set([
27678
28077
  "prd-feature",
27679
28078
  "pr-author"
27680
28079
  ]);
27681
- function isObject12(value) {
28080
+ function isObject13(value) {
27682
28081
  return typeof value === "object" && value !== null && !Array.isArray(value);
27683
28082
  }
27684
28083
  function delegatedAgents(state) {
27685
28084
  const agents = /* @__PURE__ */ new Set();
27686
28085
  let receipts = state["delegation_receipts"];
27687
- if (isObject12(receipts)) {
28086
+ if (isObject13(receipts)) {
27688
28087
  receipts = receipts["agents"];
27689
28088
  }
27690
28089
  if (Array.isArray(receipts)) {
27691
28090
  for (const receipt of receipts) {
27692
- if (!isObject12(receipt)) {
28091
+ if (!isObject13(receipt)) {
27693
28092
  continue;
27694
28093
  }
27695
28094
  const agentName = receipt["agent_name"];
@@ -27713,7 +28112,7 @@ function validateModelRoutingExistence(state) {
27713
28112
  const receipts = state["model_routing_receipts"];
27714
28113
  if (Array.isArray(receipts)) {
27715
28114
  for (const receipt of receipts) {
27716
- if (!isObject12(receipt)) {
28115
+ if (!isObject13(receipt)) {
27717
28116
  continue;
27718
28117
  }
27719
28118
  const agent = receipt["agent"];
@@ -27762,15 +28161,6 @@ var VALID_STEP_STATUS = /* @__PURE__ */ new Set([
27762
28161
  "in_progress",
27763
28162
  "completed"
27764
28163
  ]);
27765
- var VALID_BLOCKED_REASONS = /* @__PURE__ */ new Set([
27766
- "none",
27767
- "spawn_agent_unavailable",
27768
- "delegation_launch_failed",
27769
- "delegate_no_receipt",
27770
- "delegate_contract_incomplete",
27771
- "validator_failed",
27772
- "user_requested_stop"
27773
- ]);
27774
28164
  var REQUIRED_RECEIPT_KEYS = [
27775
28165
  "step",
27776
28166
  "agent_name",
@@ -27810,13 +28200,13 @@ function isValidStepStatus(key, value) {
27810
28200
  }
27811
28201
  return STEP_SPECIFIC_EXTRA_STATUS.get(key)?.has(value) === true;
27812
28202
  }
27813
- function isObject13(value) {
28203
+ function isObject14(value) {
27814
28204
  return typeof value === "object" && value !== null && !Array.isArray(value);
27815
28205
  }
27816
28206
  function validateListDelegationReceipts(receipts) {
27817
28207
  const errors = [];
27818
28208
  receipts.forEach((receipt, index) => {
27819
- if (!isObject13(receipt)) {
28209
+ if (!isObject14(receipt)) {
27820
28210
  errors.push(`Checkpoint delegation receipt #${index} must be an object.`);
27821
28211
  return;
27822
28212
  }
@@ -27858,7 +28248,7 @@ function validateNamespacedDelegationReceipts(receipts) {
27858
28248
  if (promotionReceipts === void 0 || promotionReceipts === null) {
27859
28249
  return errors;
27860
28250
  }
27861
- if (!isObject13(promotionReceipts)) {
28251
+ if (!isObject14(promotionReceipts)) {
27862
28252
  errors.push(
27863
28253
  "Checkpoint delegation_receipts.promotion must be an object namespace."
27864
28254
  );
@@ -27893,7 +28283,7 @@ function validateOrchestratorStateText(text2, options = {}) {
27893
28283
  `Checkpoint is not valid JSON: ${exc instanceof Error ? exc.message : String(exc)}`
27894
28284
  ];
27895
28285
  }
27896
- if (!isObject13(state)) {
28286
+ if (!isObject14(state)) {
27897
28287
  return ["Checkpoint root must be a JSON object."];
27898
28288
  }
27899
28289
  const stateMap = state;
@@ -27918,7 +28308,7 @@ function validateOrchestratorStateText(text2, options = {}) {
27918
28308
  if (receipts !== void 0 && receipts !== null) {
27919
28309
  if (Array.isArray(receipts)) {
27920
28310
  errors.push(...validateListDelegationReceipts(receipts));
27921
- } else if (isObject13(receipts)) {
28311
+ } else if (isObject14(receipts)) {
27922
28312
  errors.push(...validateNamespacedDelegationReceipts(receipts));
27923
28313
  } else {
27924
28314
  errors.push(
@@ -28955,10 +29345,10 @@ var PROHIBITED_ANY_LEVEL_KEYS = words(
28955
29345
  "depends_on integration_branch epic_merge_pr"
28956
29346
  );
28957
29347
  var ROOT_PATH = "<root>";
28958
- function isObject14(value) {
29348
+ function isObject15(value) {
28959
29349
  return typeof value === "object" && value !== null && !Array.isArray(value);
28960
29350
  }
28961
- function pythonRepr9(value) {
29351
+ function pythonRepr10(value) {
28962
29352
  if (value === null || value === void 0) {
28963
29353
  return "None";
28964
29354
  }
@@ -28969,18 +29359,18 @@ function pythonRepr9(value) {
28969
29359
  return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
28970
29360
  }
28971
29361
  if (Array.isArray(value)) {
28972
- return `[${value.map(pythonRepr9).join(", ")}]`;
29362
+ return `[${value.map(pythonRepr10).join(", ")}]`;
28973
29363
  }
28974
- if (isObject14(value)) {
29364
+ if (isObject15(value)) {
28975
29365
  const pairs = Object.entries(value).map(
28976
- ([key, item]) => `${pythonRepr9(key)}: ${pythonRepr9(item)}`
29366
+ ([key, item]) => `${pythonRepr10(key)}: ${pythonRepr10(item)}`
28977
29367
  );
28978
29368
  return `{${pairs.join(", ")}}`;
28979
29369
  }
28980
29370
  return String(value);
28981
29371
  }
28982
29372
  function pythonStr2(value) {
28983
- return typeof value === "string" ? value : pythonRepr9(value);
29373
+ return typeof value === "string" ? value : pythonRepr10(value);
28984
29374
  }
28985
29375
  function isEnumMember(members, value) {
28986
29376
  return typeof value === "string" && members.includes(value);
@@ -29004,13 +29394,13 @@ function inBoundedRange(value, minimum, maximum) {
29004
29394
  return isIntegral(value) && value >= minimum && value <= maximum;
29005
29395
  }
29006
29396
  function enumError(context, field, members, value) {
29007
- return `${context} ${field} must be one of ${members.join(", ")}; found: ${pythonRepr9(value)}.`;
29397
+ return `${context} ${field} must be one of ${members.join(", ")}; found: ${pythonRepr10(value)}.`;
29008
29398
  }
29009
29399
  function itemContext(context, index) {
29010
29400
  return `${context} items[${index}]`;
29011
29401
  }
29012
29402
  function validateBlastRadiusBlock(radius, context) {
29013
- if (!isObject14(radius)) {
29403
+ if (!isObject15(radius)) {
29014
29404
  return [`${context} blast_radius must be an object.`];
29015
29405
  }
29016
29406
  const errors = [];
@@ -29046,25 +29436,25 @@ function validateMergeStatus(record3, context, state) {
29046
29436
  }
29047
29437
  if (isEnumMember(MERGED_MERGE_STATUSES, mergeStatus) && state !== "merged") {
29048
29438
  return [
29049
- `${context} merge_status ${pythonRepr9(mergeStatus)} requires state 'merged'; found: ${pythonRepr9(state)}.`
29439
+ `${context} merge_status ${pythonRepr10(mergeStatus)} requires state 'merged'; found: ${pythonRepr10(state)}.`
29050
29440
  ];
29051
29441
  }
29052
29442
  if (isEnumMember(BLOCKED_MERGE_STATUSES, mergeStatus) && state !== "blocked") {
29053
29443
  return [
29054
- `${context} merge_status ${pythonRepr9(mergeStatus)} requires state 'blocked'; found: ${pythonRepr9(state)}.`
29444
+ `${context} merge_status ${pythonRepr10(mergeStatus)} requires state 'blocked'; found: ${pythonRepr10(state)}.`
29055
29445
  ];
29056
29446
  }
29057
29447
  return [];
29058
29448
  }
29059
29449
  function validateItemRecord(item, context, requireKind = false) {
29060
- if (!isObject14(item)) {
29450
+ if (!isObject15(item)) {
29061
29451
  return [`${context} must be an object.`];
29062
29452
  }
29063
29453
  const errors = [];
29064
29454
  const issueNum = item["issue_num"];
29065
29455
  if (!isPositiveInteger(issueNum)) {
29066
29456
  errors.push(
29067
- `${context} issue_num must be a positive integer; found: ${pythonRepr9(issueNum)}.`
29457
+ `${context} issue_num must be a positive integer; found: ${pythonRepr10(issueNum)}.`
29068
29458
  );
29069
29459
  }
29070
29460
  if (!isNonEmptyString2(item["feature_folder"])) {
@@ -29095,7 +29485,7 @@ function validateItems(items, context, requireKind = false) {
29095
29485
  errors.push(
29096
29486
  ...validateItemRecord(entry, itemContext(context, index), requireKind)
29097
29487
  );
29098
- if (!isObject14(entry)) {
29488
+ if (!isObject15(entry)) {
29099
29489
  return;
29100
29490
  }
29101
29491
  const issueNum = entry["issue_num"];
@@ -29114,7 +29504,7 @@ function validateItems(items, context, requireKind = false) {
29114
29504
  }
29115
29505
  function prohibitedKeyErrors(value, path16, context, keys) {
29116
29506
  const errors = [];
29117
- if (isObject14(value)) {
29507
+ if (isObject15(value)) {
29118
29508
  for (const [key, child] of Object.entries(value)) {
29119
29509
  if (keys.includes(key)) {
29120
29510
  errors.push(`${context} carries prohibited key '${key}' at ${path16}.`);
@@ -29133,7 +29523,7 @@ function prohibitedKeyErrors(value, path16, context, keys) {
29133
29523
  }
29134
29524
  function scanProhibitedKeys(root, context, deepKeys = PROHIBITED_ANY_LEVEL_KEYS, topLevelKeys = []) {
29135
29525
  const errors = prohibitedKeyErrors(root, ROOT_PATH, context, deepKeys);
29136
- if (isObject14(root) && topLevelKeys.length > 0) {
29526
+ if (isObject15(root) && topLevelKeys.length > 0) {
29137
29527
  for (const key of topLevelKeys) {
29138
29528
  if (key in root) {
29139
29529
  errors.push(
@@ -29149,7 +29539,7 @@ function scanProhibitedKeys(root, context, deepKeys = PROHIBITED_ANY_LEVEL_KEYS,
29149
29539
  var VIOLATION_PREFIX = "PARALLEL_COHORT_BARRIER_VIOLATION";
29150
29540
  var ITEM_START_TIMESTAMP_FIELD = "worktree_created_at";
29151
29541
  var MERGE_CONFIRMATION_TIMESTAMP_FIELD = "merged_at";
29152
- var NOT_STARTED_MERGE_STATUS = "not_started";
29542
+ var NOT_STARTED_MERGE_STATUS2 = "not_started";
29153
29543
  var GATING_KEYS = ["conflict_edges", "cohorts"];
29154
29544
  var FOLDER_HINT_PREFIXES = [
29155
29545
  "docs/features/active/",
@@ -29172,7 +29562,7 @@ function buildReferenceIndex(items) {
29172
29562
  return { records, byFolderHint };
29173
29563
  }
29174
29564
  for (const entry of items) {
29175
- if (!isObject14(entry)) {
29565
+ if (!isObject15(entry)) {
29176
29566
  continue;
29177
29567
  }
29178
29568
  const issueNum = entry["issue_num"];
@@ -29207,7 +29597,7 @@ function cohortIndexByItem(cohorts, recolorGeneration, references) {
29207
29597
  return assignments;
29208
29598
  }
29209
29599
  for (const entry of cohorts) {
29210
- if (!isObject14(entry) || entry["generation"] !== recolorGeneration) {
29600
+ if (!isObject15(entry) || entry["generation"] !== recolorGeneration) {
29211
29601
  continue;
29212
29602
  }
29213
29603
  const cohortIndex = entry["index"];
@@ -29224,13 +29614,13 @@ function cohortIndexByItem(cohorts, recolorGeneration, references) {
29224
29614
  }
29225
29615
  return assignments;
29226
29616
  }
29227
- function hasStarted(record3) {
29617
+ function hasStarted2(record3) {
29228
29618
  const start = record3[ITEM_START_TIMESTAMP_FIELD];
29229
29619
  if (typeof start === "string" && start.trim().length > 0) {
29230
29620
  return true;
29231
29621
  }
29232
29622
  const mergeStatus = record3["merge_status"];
29233
- return typeof mergeStatus === "string" && mergeStatus !== NOT_STARTED_MERGE_STATUS;
29623
+ return typeof mergeStatus === "string" && mergeStatus !== NOT_STARTED_MERGE_STATUS2;
29234
29624
  }
29235
29625
  function satisfiesBarrier(record3) {
29236
29626
  return isEnumMember(MERGED_MERGE_STATUSES, record3["merge_status"]);
@@ -29258,7 +29648,7 @@ function violationEndpoints(first, second, assignments, records) {
29258
29648
  if (earlier === void 0 || later === void 0) {
29259
29649
  return null;
29260
29650
  }
29261
- const statusViolation = hasStarted(later) && !satisfiesBarrier(earlier);
29651
+ const statusViolation = hasStarted2(later) && !satisfiesBarrier(earlier);
29262
29652
  if (statusViolation || mergeConfirmedAfterStart(earlier, later)) {
29263
29653
  return [earlierKey, laterKey];
29264
29654
  }
@@ -29280,7 +29670,7 @@ function validateCohortBarrierOrdering(state) {
29280
29670
  );
29281
29671
  const errors = [];
29282
29672
  for (const entry of edges) {
29283
- if (!isObject14(entry)) {
29673
+ if (!isObject15(entry)) {
29284
29674
  continue;
29285
29675
  }
29286
29676
  const first = resolveReference(entry["a"], references);
@@ -29318,14 +29708,14 @@ function validateMutationItemKey(entry, entryContext, op, issueNums) {
29318
29708
  if (op === "close") {
29319
29709
  if (!isNone(itemKey)) {
29320
29710
  return [
29321
- `${entryContext} item_key must be null for op 'close'; found: ${pythonRepr9(itemKey)}.`
29711
+ `${entryContext} item_key must be null for op 'close'; found: ${pythonRepr10(itemKey)}.`
29322
29712
  ];
29323
29713
  }
29324
29714
  return [];
29325
29715
  }
29326
29716
  if (isEnumMember(OPS_REQUIRING_ITEM_KEY, op) && !resolves(itemKey, issueNums)) {
29327
29717
  return [
29328
- `${entryContext} item_key ${pythonRepr9(itemKey)} does not resolve to an items[].issue_num.`
29718
+ `${entryContext} item_key ${pythonRepr10(itemKey)} does not resolve to an items[].issue_num.`
29329
29719
  ];
29330
29720
  }
29331
29721
  return [];
@@ -29337,12 +29727,12 @@ function validateMutationStateField(entry, entryContext, field, op, nullOps) {
29337
29727
  }
29338
29728
  if (isEnumMember(nullOps, op)) {
29339
29729
  return [
29340
- `${entryContext} ${field} must be null for op ${pythonRepr9(op)}; found: ${pythonRepr9(value)}.`
29730
+ `${entryContext} ${field} must be null for op ${pythonRepr10(op)}; found: ${pythonRepr10(value)}.`
29341
29731
  ];
29342
29732
  }
29343
29733
  if (!isEnumMember(VALID_ITEM_STATES, value)) {
29344
29734
  return [
29345
- `${entryContext} ${field} must be null or one of ${VALID_ITEM_STATES.join(", ")}; found: ${pythonRepr9(value)}.`
29735
+ `${entryContext} ${field} must be null or one of ${VALID_ITEM_STATES.join(", ")}; found: ${pythonRepr10(value)}.`
29346
29736
  ];
29347
29737
  }
29348
29738
  return [];
@@ -29352,14 +29742,14 @@ function validateMutationDisposition(entry, entryContext, op) {
29352
29742
  if (op === "remove" && entry["prior_state"] === "in_flight") {
29353
29743
  if (!isEnumMember(VALID_DISPOSITIONS, disposition)) {
29354
29744
  return [
29355
- `${entryContext} disposition must be one of ${VALID_DISPOSITIONS.join(", ")} for an in-flight removal; found: ${pythonRepr9(disposition)}.`
29745
+ `${entryContext} disposition must be one of ${VALID_DISPOSITIONS.join(", ")} for an in-flight removal; found: ${pythonRepr10(disposition)}.`
29356
29746
  ];
29357
29747
  }
29358
29748
  return [];
29359
29749
  }
29360
29750
  if (!isNone(disposition)) {
29361
29751
  return [
29362
- `${entryContext} disposition must be null unless op is 'remove' with prior_state 'in_flight'; found: ${pythonRepr9(disposition)}.`
29752
+ `${entryContext} disposition must be null unless op is 'remove' with prior_state 'in_flight'; found: ${pythonRepr10(disposition)}.`
29363
29753
  ];
29364
29754
  }
29365
29755
  return [];
@@ -29368,7 +29758,7 @@ function validateMutationGeneration(entry, entryContext, recolorGeneration) {
29368
29758
  const generation = entry["recolor_generation"];
29369
29759
  if (!isNonNegativeInteger(generation)) {
29370
29760
  return [
29371
- `${entryContext} recolor_generation must be a non-negative integer; found: ${pythonRepr9(generation)}.`
29761
+ `${entryContext} recolor_generation must be a non-negative integer; found: ${pythonRepr10(generation)}.`
29372
29762
  ];
29373
29763
  }
29374
29764
  if (isNonNegativeInteger(recolorGeneration) && typeof generation === "number" && typeof recolorGeneration === "number" && generation > recolorGeneration) {
@@ -29385,7 +29775,7 @@ function validateMutations(mutations, issueNums, recolorGeneration, context) {
29385
29775
  const errors = [];
29386
29776
  mutations.forEach((entry, position) => {
29387
29777
  const entryContext = `${context} mutations[${position}]`;
29388
- if (!isObject14(entry)) {
29778
+ if (!isObject15(entry)) {
29389
29779
  errors.push(`${entryContext} must be an object.`);
29390
29780
  return;
29391
29781
  }
@@ -29429,14 +29819,14 @@ function validateDriftEvents(events, issueNums, context) {
29429
29819
  const errors = [];
29430
29820
  events.forEach((entry, position) => {
29431
29821
  const entryContext = `${context} drift_events[${position}]`;
29432
- if (!isObject14(entry)) {
29822
+ if (!isObject15(entry)) {
29433
29823
  errors.push(`${entryContext} must be an object.`);
29434
29824
  return;
29435
29825
  }
29436
29826
  const itemKey = entry["item_key"];
29437
29827
  if (!resolves(itemKey, issueNums)) {
29438
29828
  errors.push(
29439
- `${entryContext} item_key ${pythonRepr9(itemKey)} does not resolve to an items[].issue_num.`
29829
+ `${entryContext} item_key ${pythonRepr10(itemKey)} does not resolve to an items[].issue_num.`
29440
29830
  );
29441
29831
  }
29442
29832
  for (const field of ["declared", "observed"]) {
@@ -29474,7 +29864,7 @@ function collectItemKeysAndStates(items) {
29474
29864
  return pairs;
29475
29865
  }
29476
29866
  for (const entry of items) {
29477
- if (!isObject14(entry)) {
29867
+ if (!isObject15(entry)) {
29478
29868
  continue;
29479
29869
  }
29480
29870
  const issueNum = entry["issue_num"];
@@ -29492,13 +29882,13 @@ function validateCohortEntry(entry, entryContext, issueNums, recolorGeneration)
29492
29882
  const index = entry["index"];
29493
29883
  if (!isNonNegativeInteger(index)) {
29494
29884
  errors.push(
29495
- `${entryContext} index must be a non-negative integer; found: ${pythonRepr9(index)}.`
29885
+ `${entryContext} index must be a non-negative integer; found: ${pythonRepr10(index)}.`
29496
29886
  );
29497
29887
  }
29498
29888
  const generation = entry["generation"];
29499
29889
  if (!isNonNegativeInteger(generation)) {
29500
29890
  errors.push(
29501
- `${entryContext} generation must be a non-negative integer; found: ${pythonRepr9(generation)}.`
29891
+ `${entryContext} generation must be a non-negative integer; found: ${pythonRepr10(generation)}.`
29502
29892
  );
29503
29893
  } else if (recolorGeneration !== null && typeof generation === "number" && generation > recolorGeneration) {
29504
29894
  errors.push(
@@ -29513,7 +29903,7 @@ function validateCohortEntry(entry, entryContext, issueNums, recolorGeneration)
29513
29903
  for (const key of itemKeys) {
29514
29904
  if (typeof key !== "number" || !Number.isInteger(key) || !issueNums.has(key)) {
29515
29905
  errors.push(
29516
- `${entryContext} item_keys entry ${pythonRepr9(key)} does not resolve to an items[].issue_num.`
29906
+ `${entryContext} item_keys entry ${pythonRepr10(key)} does not resolve to an items[].issue_num.`
29517
29907
  );
29518
29908
  }
29519
29909
  }
@@ -29524,7 +29914,7 @@ function validateCohortShapes(cohorts, issueNums, recolorGeneration, context) {
29524
29914
  const generationOk = isNonNegativeInteger(recolorGeneration);
29525
29915
  if (!generationOk) {
29526
29916
  errors.push(
29527
- `${context} recolor_generation must be a non-negative integer; found: ${pythonRepr9(recolorGeneration)}.`
29917
+ `${context} recolor_generation must be a non-negative integer; found: ${pythonRepr10(recolorGeneration)}.`
29528
29918
  );
29529
29919
  }
29530
29920
  if (!Array.isArray(cohorts)) {
@@ -29534,7 +29924,7 @@ function validateCohortShapes(cohorts, issueNums, recolorGeneration, context) {
29534
29924
  const bound = generationOk && typeof recolorGeneration === "number" ? recolorGeneration : null;
29535
29925
  cohorts.forEach((entry, position) => {
29536
29926
  const entryContext = `${context} cohorts[${position}]`;
29537
- if (!isObject14(entry)) {
29927
+ if (!isObject15(entry)) {
29538
29928
  errors.push(`${entryContext} must be an object.`);
29539
29929
  return;
29540
29930
  }
@@ -29546,7 +29936,7 @@ function currentGenerationCohorts(cohorts, recolorGeneration) {
29546
29936
  if (!isNonNegativeInteger(recolorGeneration) || !Array.isArray(cohorts)) {
29547
29937
  return [];
29548
29938
  }
29549
- return cohorts.filter(isObject14).filter((entry) => entry["generation"] === recolorGeneration);
29939
+ return cohorts.filter(isObject15).filter((entry) => entry["generation"] === recolorGeneration);
29550
29940
  }
29551
29941
  function validateCurrentGenerationCohorts(cohorts, items, recolorGeneration, context) {
29552
29942
  const current = currentGenerationCohorts(cohorts, recolorGeneration);
@@ -29591,7 +29981,7 @@ function validateCurrentGenerationCohorts(cohorts, items, recolorGeneration, con
29591
29981
  continue;
29592
29982
  }
29593
29983
  errors.push(
29594
- `${context} item ${issueNum} in state ${pythonRepr9(state)} must appear in exactly one current-generation cohort; found ${count}.`
29984
+ `${context} item ${issueNum} in state ${pythonRepr10(state)} must appear in exactly one current-generation cohort; found ${count}.`
29595
29985
  );
29596
29986
  }
29597
29987
  return errors;
@@ -29599,7 +29989,7 @@ function validateCurrentGenerationCohorts(cohorts, items, recolorGeneration, con
29599
29989
  function validateCurrentCohortBound(currentCohort, cohorts, recolorGeneration, context) {
29600
29990
  if (!isNonNegativeInteger(currentCohort) || typeof currentCohort !== "number") {
29601
29991
  return [
29602
- `${context} current_cohort must be a non-negative integer; found: ${pythonRepr9(currentCohort)}.`
29992
+ `${context} current_cohort must be a non-negative integer; found: ${pythonRepr10(currentCohort)}.`
29603
29993
  ];
29604
29994
  }
29605
29995
  const indices = [];
@@ -29629,7 +30019,7 @@ function validateEdgeEndpoints(entry, entryContext, issueNums) {
29629
30019
  endpoints.set(field, value);
29630
30020
  } else {
29631
30021
  errors.push(
29632
- `${entryContext} ${field} ${pythonRepr9(value)} does not resolve to an items[].issue_num.`
30022
+ `${entryContext} ${field} ${pythonRepr10(value)} does not resolve to an items[].issue_num.`
29633
30023
  );
29634
30024
  }
29635
30025
  }
@@ -29659,7 +30049,7 @@ function validateConflictEdges(edges, issueNums, context) {
29659
30049
  const duplicates = /* @__PURE__ */ new Map();
29660
30050
  edges.forEach((entry, position) => {
29661
30051
  const entryContext = `${context} conflict_edges[${position}]`;
29662
- if (!isObject14(entry)) {
30052
+ if (!isObject15(entry)) {
29663
30053
  errors.push(`${entryContext} must be an object.`);
29664
30054
  return;
29665
30055
  }
@@ -29738,7 +30128,7 @@ function validateIdentity(state) {
29738
30128
  const routeId = state["route_id"];
29739
30129
  if ("route_id" in state && routeId !== EXPECTED_ROUTE_ID2) {
29740
30130
  errors.push(
29741
- `${CONTEXT} route_id must be '${EXPECTED_ROUTE_ID2}'; found: ${pythonRepr9(routeId)}.`
30131
+ `${CONTEXT} route_id must be '${EXPECTED_ROUTE_ID2}'; found: ${pythonRepr10(routeId)}.`
29742
30132
  );
29743
30133
  }
29744
30134
  const mode = state["mode"];
@@ -29748,7 +30138,7 @@ function validateIdentity(state) {
29748
30138
  const concurrency = state["max_concurrency"];
29749
30139
  if ("max_concurrency" in state && !inBoundedRange(concurrency, MIN_CONCURRENCY, MAX_CONCURRENCY)) {
29750
30140
  errors.push(
29751
- `${CONTEXT} max_concurrency must be an integer from ${MIN_CONCURRENCY} through ${MAX_CONCURRENCY}; found: ${pythonRepr9(concurrency)}.`
30141
+ `${CONTEXT} max_concurrency must be an integer from ${MIN_CONCURRENCY} through ${MAX_CONCURRENCY}; found: ${pythonRepr10(concurrency)}.`
29752
30142
  );
29753
30143
  }
29754
30144
  return errors;
@@ -29804,7 +30194,7 @@ function recordsCloseMutation(state) {
29804
30194
  return false;
29805
30195
  }
29806
30196
  return mutations.some(
29807
- (entry) => isObject14(entry) && entry["op"] === "close"
30197
+ (entry) => isObject15(entry) && entry["op"] === "close"
29808
30198
  );
29809
30199
  }
29810
30200
  function validateCompletion2(state) {
@@ -29812,7 +30202,7 @@ function validateCompletion2(state) {
29812
30202
  const items = state["items"];
29813
30203
  const entries = Array.isArray(items) ? items : [];
29814
30204
  entries.forEach((entry, index) => {
29815
- if (!isObject14(entry)) {
30205
+ if (!isObject15(entry)) {
29816
30206
  return;
29817
30207
  }
29818
30208
  if (entry["state"] === "withdrawn") {
@@ -29821,7 +30211,7 @@ function validateCompletion2(state) {
29821
30211
  const mergeStatus = entry["merge_status"];
29822
30212
  if (!isEnumMember(MERGED_MERGE_STATUSES, mergeStatus)) {
29823
30213
  errors.push(
29824
- `${itemContext(CONTEXT, index)} completion validation failed: merge_status is not merged or worktree_removed; found: ${pythonRepr9(mergeStatus)}.`
30214
+ `${itemContext(CONTEXT, index)} completion validation failed: merge_status is not merged or worktree_removed; found: ${pythonRepr10(mergeStatus)}.`
29825
30215
  );
29826
30216
  }
29827
30217
  });
@@ -29840,7 +30230,7 @@ function validateParallelOrchestratorStateText(text2, options = {}) {
29840
30230
  const detail = error2 instanceof Error ? error2.message : String(error2);
29841
30231
  return [`${CONTEXT} is not valid JSON: ${detail}.`];
29842
30232
  }
29843
- if (!isObject14(state)) {
30233
+ if (!isObject15(state)) {
29844
30234
  return [`${CONTEXT} root must be a JSON object.`];
29845
30235
  }
29846
30236
  const errors = [];
@@ -29918,7 +30308,7 @@ function validateIdentity2(state) {
29918
30308
  const concurrency = state["max_concurrency"];
29919
30309
  if ("max_concurrency" in state && !inBoundedRange(concurrency, MIN_CONCURRENCY2, MAX_CONCURRENCY2)) {
29920
30310
  errors.push(
29921
- `${CONTEXT2} max_concurrency must be an integer from ${MIN_CONCURRENCY2} through ${MAX_CONCURRENCY2}; found: ${pythonRepr9(concurrency)}.`
30311
+ `${CONTEXT2} max_concurrency must be an integer from ${MIN_CONCURRENCY2} through ${MAX_CONCURRENCY2}; found: ${pythonRepr10(concurrency)}.`
29922
30312
  );
29923
30313
  }
29924
30314
  return errors;
@@ -29929,7 +30319,7 @@ function itemRecords(items) {
29929
30319
  }
29930
30320
  const records = [];
29931
30321
  items.forEach((entry, index) => {
29932
- if (isObject14(entry)) {
30322
+ if (isObject15(entry)) {
29933
30323
  records.push({ index, record: entry });
29934
30324
  }
29935
30325
  });
@@ -29998,13 +30388,13 @@ function validateReadyItem(record3, entryContext) {
29998
30388
  const preparationStatus = record3["preparation_status"];
29999
30389
  if (preparationStatus !== READY_PREPARATION_STATUS) {
30000
30390
  errors.push(
30001
- `${entryContext} preparation_status must be ${pythonRepr9(READY_PREPARATION_STATUS)}; found: ${pythonRepr9(preparationStatus)}.`
30391
+ `${entryContext} preparation_status must be ${pythonRepr10(READY_PREPARATION_STATUS)}; found: ${pythonRepr10(preparationStatus)}.`
30002
30392
  );
30003
30393
  }
30004
30394
  const preflightStatus = record3["preflight_status"];
30005
30395
  if (preflightStatus !== READY_PREFLIGHT_STATUS) {
30006
30396
  errors.push(
30007
- `${entryContext} preflight_status must be ${pythonRepr9(READY_PREFLIGHT_STATUS)}; found: ${pythonRepr9(preflightStatus)}.`
30397
+ `${entryContext} preflight_status must be ${pythonRepr10(READY_PREFLIGHT_STATUS)}; found: ${pythonRepr10(preflightStatus)}.`
30008
30398
  );
30009
30399
  }
30010
30400
  for (const key of READY_ITEM_PATH_KEYS) {
@@ -30013,10 +30403,10 @@ function validateReadyItem(record3, entryContext) {
30013
30403
  }
30014
30404
  }
30015
30405
  const radius = record3["blast_radius"];
30016
- const source = isObject14(radius) ? radius["source"] : null;
30406
+ const source = isObject15(radius) ? radius["source"] : null;
30017
30407
  if (source !== READY_RADIUS_SOURCE) {
30018
30408
  errors.push(
30019
- `${entryContext} blast_radius.source must be ${pythonRepr9(READY_RADIUS_SOURCE)} for execution readiness; found: ${pythonRepr9(source)}.`
30409
+ `${entryContext} blast_radius.source must be ${pythonRepr10(READY_RADIUS_SOURCE)} for execution readiness; found: ${pythonRepr10(source)}.`
30020
30410
  );
30021
30411
  }
30022
30412
  return errors;
@@ -30038,14 +30428,14 @@ function validateReadyGate(state) {
30038
30428
  const nextStep = state["next_step"];
30039
30429
  if (nextStep !== READY_NEXT_STEP2) {
30040
30430
  errors.push(
30041
- `${CONTEXT2} next_step must be ${pythonRepr9(READY_NEXT_STEP2)}; found: ${pythonRepr9(nextStep)}.`
30431
+ `${CONTEXT2} next_step must be ${pythonRepr10(READY_NEXT_STEP2)}; found: ${pythonRepr10(nextStep)}.`
30042
30432
  );
30043
30433
  }
30044
30434
  const expectedKickoff = kickoffPathFor(state["parallel_slug"]);
30045
30435
  const kickoffPromptPath = state["kickoff_prompt_path"];
30046
30436
  if (kickoffPromptPath !== expectedKickoff) {
30047
30437
  errors.push(
30048
- `${CONTEXT2} kickoff_prompt_path must be ${pythonRepr9(expectedKickoff)}; found: ${pythonRepr9(kickoffPromptPath)}.`
30438
+ `${CONTEXT2} kickoff_prompt_path must be ${pythonRepr10(expectedKickoff)}; found: ${pythonRepr10(kickoffPromptPath)}.`
30049
30439
  );
30050
30440
  }
30051
30441
  return errors;
@@ -30058,7 +30448,7 @@ function validateParallelPlannerStateText(text2, options = {}) {
30058
30448
  const detail = error2 instanceof Error ? error2.message : String(error2);
30059
30449
  return [`${CONTEXT2} is not valid JSON: ${detail}.`];
30060
30450
  }
30061
- if (!isObject14(state)) {
30451
+ if (!isObject15(state)) {
30062
30452
  return [`${CONTEXT2} root must be a JSON object.`];
30063
30453
  }
30064
30454
  const errors = [];
@@ -35873,6 +36263,10 @@ function promotePotential(options) {
35873
36263
  filesystem.ensureDir(promotedDir);
35874
36264
  const destPath = posixJoin(promotedDir, posixBasename(resolved));
35875
36265
  filesystem.move(resolved, destPath);
36266
+ if (!filesystem.exists(destPath)) {
36267
+ emitLine(`Promoted file missing after move: ${destPath}`);
36268
+ return { exitCode: 1, messages };
36269
+ }
35876
36270
  emitLine(`Moved potential file to promoted folder: ${destPath}`);
35877
36271
  return { exitCode: 0, messages, destination: destPath };
35878
36272
  }