@danmoisan/drm-copilot-mcp 1.1.22 → 1.1.24

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 (261) hide show
  1. package/out/mcp-server.js +18758 -12030
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +1 -1
  4. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_test_files_count_against_500_cap.md +4 -4
  5. package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +1 -1
  6. package/resources/claude-customizations/.claude/agents/discovery-capability-sentinel.md +34 -0
  7. package/resources/claude-customizations/.claude/agents/feature-review.md +8 -0
  8. package/resources/claude-customizations/.claude/agents/legacy-parity-analyst.md +101 -43
  9. package/resources/claude-customizations/.claude/agents/migration-coverage-reviewer.md +107 -43
  10. package/resources/claude-customizations/.claude/agents/orchestrator.md +1 -1
  11. package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +60 -6
  12. package/resources/claude-customizations/.claude/agents/parallel-planner.md +21 -1
  13. package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +1 -1
  14. package/resources/claude-customizations/.claude/agents/pr-author.md +48 -7
  15. package/resources/claude-customizations/.claude/agents/python-typed-engineer.md +1 -1
  16. package/resources/claude-customizations/.claude/agents/requirements-reconciler.md +117 -42
  17. package/resources/claude-customizations/.claude/agents/runtime-characterization-analyst.md +103 -43
  18. package/resources/claude-customizations/.claude/hooks/discovery-capability-probe.ps1 +102 -0
  19. package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +69 -194
  20. package/resources/claude-customizations/.claude/hooks/enforce-discovery-planning-gate.ps1 +87 -0
  21. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-green-ci.ps1 +325 -0
  22. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +29 -7
  23. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +23 -10
  24. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +29 -21
  25. package/resources/claude-customizations/.claude/hooks/enforce-file-size-limit.ps1 +244 -0
  26. package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +51 -0
  27. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +168 -48
  28. package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +1 -1
  29. package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +22 -11
  30. package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +59 -20
  31. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +51 -4
  32. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +72 -11
  33. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.current-branch.ps1 +149 -0
  34. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.epic-base-branch.ps1 +4 -2
  35. package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +59 -20
  36. package/resources/claude-customizations/.claude/hooks/record-discovery-agent-start.ps1 +132 -0
  37. package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +56 -212
  38. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-feature-folder.ps1 +146 -0
  39. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-rejection.ps1 +172 -0
  40. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +34 -4
  41. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +9 -3
  42. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusAggregate.psm1 +154 -0
  43. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusCombination.psm1 +228 -0
  44. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +1 -0
  45. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusNormalization.psm1 +4 -2
  46. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusScheduling.psm1 +63 -16
  47. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +56 -1
  48. package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusWriteIntent.psm1 +4 -1
  49. package/resources/claude-customizations/.claude/lib/cleanup-manifest/CleanupWorktreeManifest.psm1 +33 -6
  50. package/resources/claude-customizations/.claude/lib/codex-routing/CodexDeployment.psm1 +5 -1
  51. package/resources/claude-customizations/.claude/lib/codex-routing/CodexDiscoveryRouting.psm1 +161 -0
  52. package/resources/claude-customizations/.claude/lib/codex-routing/CodexTopology.psm1 +25 -2
  53. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthority.psd1 +90 -0
  54. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthority.psm1 +493 -0
  55. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthorization.psm1 +479 -0
  56. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryCapability.psm1 +468 -0
  57. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryEncoding.psm1 +156 -0
  58. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryManifest.psm1 +384 -0
  59. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryObservation.psm1 +217 -0
  60. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryPayload.psm1 +276 -0
  61. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryPlanning.psm1 +336 -0
  62. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryRootGrant.psm1 +164 -0
  63. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStart.psm1 +440 -0
  64. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStartRecord.psm1 +296 -0
  65. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStop.psm1 +336 -0
  66. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryToolRouting.psm1 +228 -0
  67. package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryValidation.psm1 +188 -341
  68. package/resources/claude-customizations/.claude/lib/file-size-policy/FileSizePolicy.psm1 +434 -0
  69. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateFeatureFolderRecord.psm1 +166 -0
  70. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +8 -3
  71. package/resources/claude-customizations/.claude/lib/worktree-resolution/HookTargetWorktree.psm1 +391 -0
  72. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunRecordPath.psm1 +185 -0
  73. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +11 -21
  74. package/resources/claude-customizations/.claude/rules/general-code-change.md +4 -1
  75. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +29 -5
  76. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +152 -20
  77. package/resources/claude-customizations/.claude/rules/powershell.md +1 -1
  78. package/resources/claude-customizations/.claude/rules/shell.md +1 -1
  79. package/resources/claude-customizations/.claude/settings.json +36 -3
  80. package/resources/claude-customizations/.claude/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
  81. package/resources/claude-customizations/.claude/skills/characterize-runtime-behavior/SKILL.md +134 -0
  82. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +2 -2
  83. package/resources/claude-customizations/.claude/skills/discovery-behavior-reconciliation/SKILL.md +28 -47
  84. package/resources/claude-customizations/.claude/skills/discovery-coverage-ledger/SKILL.md +32 -48
  85. package/resources/claude-customizations/.claude/skills/discovery-parity-matrix/SKILL.md +28 -45
  86. package/resources/claude-customizations/.claude/skills/discovery-repo-inventory/SKILL.md +28 -62
  87. package/resources/claude-customizations/.claude/skills/discovery-runtime-characterization/SKILL.md +28 -45
  88. package/resources/claude-customizations/.claude/skills/discovery-validate-artifacts/SKILL.md +28 -61
  89. package/resources/claude-customizations/.claude/skills/discovery-workflow/SKILL.md +55 -139
  90. package/resources/claude-customizations/.claude/skills/execution-environment/SKILL.md +25 -10
  91. package/resources/claude-customizations/.claude/skills/extract-feature-contract/SKILL.md +133 -0
  92. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +1 -0
  93. package/resources/claude-customizations/.claude/skills/generate-acceptance-scenarios/SKILL.md +132 -0
  94. package/resources/claude-customizations/.claude/skills/initialize-discovery-workspace/SKILL.md +131 -0
  95. package/resources/claude-customizations/.claude/skills/inventory-legacy-system/SKILL.md +131 -0
  96. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +15 -7
  97. package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +25 -2
  98. package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +11 -1
  99. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +124 -14
  100. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +72 -7
  101. package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +15 -0
  102. package/resources/claude-customizations/.claude/skills/parallel-run/SKILL.md +6 -0
  103. package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +56 -9
  104. package/resources/claude-customizations/.claude/skills/reconcile-parity-matrix/SKILL.md +131 -0
  105. package/resources/claude-customizations/.claude/skills/review-discovery-coverage/SKILL.md +129 -0
  106. package/resources/claude-customizations/.claude/skills/validate-discovery-artifacts/SKILL.md +127 -0
  107. package/resources/claude-customizations/.claude-variants/csharp-legacy/agents/csharp-typed-engineer.md +1 -1
  108. package/resources/claude-customizations/config/blast-radius.json +6 -5
  109. package/resources/claude-customizations/config/orchestration-routing.json +61 -1
  110. package/resources/claude-customizations/pack-manifests/core.json +40 -1
  111. package/resources/codex-and-agents-customizations/.agents/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
  112. package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +7 -0
  113. package/resources/codex-and-agents-customizations/.agents/skills/characterize-runtime-behavior/SKILL.md +134 -0
  114. package/resources/codex-and-agents-customizations/.agents/skills/discovery-behavior-reconciliation/SKILL.md +46 -0
  115. package/resources/codex-and-agents-customizations/.agents/skills/discovery-coverage-ledger/SKILL.md +50 -0
  116. package/resources/codex-and-agents-customizations/.agents/skills/discovery-parity-matrix/SKILL.md +46 -0
  117. package/resources/codex-and-agents-customizations/.agents/skills/discovery-repo-inventory/SKILL.md +46 -0
  118. package/resources/codex-and-agents-customizations/.agents/skills/discovery-runtime-characterization/SKILL.md +46 -0
  119. package/resources/codex-and-agents-customizations/.agents/skills/discovery-validate-artifacts/SKILL.md +46 -0
  120. package/resources/codex-and-agents-customizations/.agents/skills/discovery-workflow/SKILL.md +62 -0
  121. package/resources/codex-and-agents-customizations/.agents/skills/execution-environment/SKILL.md +25 -10
  122. package/resources/codex-and-agents-customizations/.agents/skills/extract-feature-contract/SKILL.md +133 -0
  123. package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
  124. package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +8 -0
  125. package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +4 -1
  126. package/resources/codex-and-agents-customizations/.agents/skills/generate-acceptance-scenarios/SKILL.md +132 -0
  127. package/resources/codex-and-agents-customizations/.agents/skills/initialize-discovery-workspace/SKILL.md +131 -0
  128. package/resources/codex-and-agents-customizations/.agents/skills/inventory-legacy-system/SKILL.md +131 -0
  129. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +8 -0
  130. package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +1 -1
  131. package/resources/codex-and-agents-customizations/.agents/skills/reconcile-parity-matrix/SKILL.md +131 -0
  132. package/resources/codex-and-agents-customizations/.agents/skills/review-discovery-coverage/SKILL.md +129 -0
  133. package/resources/codex-and-agents-customizations/.agents/skills/validate-discovery-artifacts/SKILL.md +127 -0
  134. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c1.toml +1 -1
  135. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c2.toml +1 -1
  136. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3-elevated.toml +1 -1
  137. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3.toml +1 -1
  138. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c4.toml +1 -1
  139. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer.toml +1 -1
  140. package/resources/codex-and-agents-customizations/.codex/agents/discovery-capability-sentinel.toml +51 -0
  141. package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +8 -0
  142. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c1.toml +148 -0
  143. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c2.toml +148 -0
  144. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c3-elevated.toml +148 -0
  145. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c3.toml +148 -0
  146. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c4.toml +148 -0
  147. package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst.toml +148 -0
  148. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c1.toml +154 -0
  149. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c2.toml +154 -0
  150. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c3-elevated.toml +154 -0
  151. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c3.toml +154 -0
  152. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c4.toml +154 -0
  153. package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer.toml +154 -0
  154. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c1.toml +1 -1
  155. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c2.toml +1 -1
  156. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3-elevated.toml +1 -1
  157. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3.toml +1 -1
  158. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c4.toml +1 -1
  159. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +1 -1
  160. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c1.toml +1 -1
  161. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c2.toml +1 -1
  162. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3-elevated.toml +1 -1
  163. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3.toml +1 -1
  164. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c4.toml +1 -1
  165. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer.toml +1 -1
  166. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c1.toml +164 -0
  167. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c2.toml +164 -0
  168. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c3-elevated.toml +164 -0
  169. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c3.toml +164 -0
  170. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c4.toml +164 -0
  171. package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler.toml +164 -0
  172. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c1.toml +150 -0
  173. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c2.toml +150 -0
  174. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c3-elevated.toml +150 -0
  175. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c3.toml +150 -0
  176. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c4.toml +150 -0
  177. package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst.toml +150 -0
  178. package/resources/codex-and-agents-customizations/.codex/config.toml +39 -3
  179. package/resources/codex-and-agents-customizations/.codex/hooks/codex-agent-profile-attestation.ps1 +22 -0
  180. package/resources/codex-and-agents-customizations/.codex/hooks/discovery-capability-probe.ps1 +97 -0
  181. package/resources/codex-and-agents-customizations/.codex/hooks/discovery-start-attestation.ps1 +171 -0
  182. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +4 -1
  183. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-discovery-artifact-gate.ps1 +187 -0
  184. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-discovery-planning-gate.ps1 +149 -0
  185. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-file-size-limit.ps1 +282 -0
  186. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +239 -2
  187. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +6 -15
  188. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +54 -15
  189. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +54 -15
  190. package/resources/codex-and-agents-customizations/.codex/hooks/file-size-policy.ps1 +421 -0
  191. package/resources/codex-and-agents-customizations/.codex/hooks/hook-target-worktree.ps1 +369 -0
  192. package/resources/codex-and-agents-customizations/.codex/hooks/record-subagent-routing-attestation.ps1 +8 -0
  193. package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +22 -1
  194. package/resources/codex-and-agents-customizations/.codex/hooks/validate-discovery-agent-output.ps1 +178 -0
  195. package/resources/codex-and-agents-customizations/.codex/scripts/Resolve-CodexTopology.ps1 +11 -1
  196. package/resources/codex-and-agents-customizations/.codex-variants/csharp-legacy/agents/csharp-typed-engineer.toml +1 -1
  197. package/resources/codex-and-agents-customizations/AGENTS.md +4 -1
  198. package/resources/codex-and-agents-customizations/pack-manifests/core.json +65 -1
  199. package/resources/config/orchestration-routing.json +61 -1
  200. package/resources/customizations/.github/agents/commentary-remediation.agent.md +1 -1
  201. package/resources/customizations/.github/agents/discovery-capability-sentinel.agent.md +34 -0
  202. package/resources/customizations/.github/agents/legacy-parity-analyst.agent.md +122 -0
  203. package/resources/customizations/.github/agents/migration-coverage-reviewer.agent.md +128 -0
  204. package/resources/customizations/.github/agents/python-execution-only-typed.agent.md +1 -1
  205. package/resources/customizations/.github/agents/python-typed-engineer.agent.md +1 -1
  206. package/resources/customizations/.github/agents/requirements-reconciler.agent.md +138 -0
  207. package/resources/customizations/.github/agents/runtime-characterization-analyst.agent.md +124 -0
  208. package/resources/customizations/.github/hooks/discovery-agent-start.ps1 +139 -0
  209. package/resources/customizations/.github/hooks/discovery-agent-stop.ps1 +123 -0
  210. package/resources/customizations/.github/hooks/discovery-capability-probe.ps1 +98 -0
  211. package/resources/customizations/.github/hooks/discovery-planning.ps1 +91 -0
  212. package/resources/customizations/.github/hooks/discovery-pre-tool.ps1 +123 -0
  213. package/resources/customizations/.github/hooks/discovery.json +35 -0
  214. package/resources/customizations/.github/instructions/general-code-change.instructions.md +5 -2
  215. package/resources/customizations/.github/instructions/mermaid.instructions.md +85 -0
  216. package/resources/customizations/.github/instructions/powershell-code-change.instructions.md +1 -1
  217. package/resources/customizations/.github/prompts/execute-hard-lock.prompt.md +105 -0
  218. package/resources/customizations/.github/prompts/remediate-comments.prompt.md +1 -1
  219. package/resources/customizations/.github/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
  220. package/resources/customizations/.github/skills/characterize-runtime-behavior/SKILL.md +134 -0
  221. package/resources/customizations/.github/skills/discovery-behavior-reconciliation/SKILL.md +46 -0
  222. package/resources/customizations/.github/skills/discovery-coverage-ledger/SKILL.md +50 -0
  223. package/resources/customizations/.github/skills/discovery-parity-matrix/SKILL.md +46 -0
  224. package/resources/customizations/.github/skills/discovery-repo-inventory/SKILL.md +46 -0
  225. package/resources/customizations/.github/skills/discovery-runtime-characterization/SKILL.md +46 -0
  226. package/resources/customizations/.github/skills/discovery-validate-artifacts/SKILL.md +46 -0
  227. package/resources/customizations/.github/skills/discovery-workflow/SKILL.md +62 -0
  228. package/resources/customizations/.github/skills/execution-environment/SKILL.md +25 -10
  229. package/resources/customizations/.github/skills/extract-feature-contract/SKILL.md +133 -0
  230. package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +8 -0
  231. package/resources/customizations/.github/skills/generate-acceptance-scenarios/SKILL.md +132 -0
  232. package/resources/customizations/.github/skills/initialize-discovery-workspace/SKILL.md +131 -0
  233. package/resources/customizations/.github/skills/inventory-legacy-system/SKILL.md +131 -0
  234. package/resources/customizations/.github/skills/reconcile-parity-matrix/SKILL.md +131 -0
  235. package/resources/customizations/.github/skills/review-discovery-coverage/SKILL.md +129 -0
  236. package/resources/customizations/.github/skills/validate-discovery-artifacts/SKILL.md +127 -0
  237. package/resources/lib/codex-routing/CodexDeployment.psm1 +5 -1
  238. package/resources/lib/codex-routing/CodexDiscoveryRouting.psm1 +161 -0
  239. package/resources/lib/codex-routing/CodexTopology.psm1 +25 -2
  240. package/resources/lib/discovery-validation/DiscoveryAuthority.psd1 +90 -0
  241. package/resources/lib/discovery-validation/DiscoveryAuthority.psm1 +493 -0
  242. package/resources/lib/discovery-validation/DiscoveryAuthorization.psm1 +479 -0
  243. package/resources/lib/discovery-validation/DiscoveryCapability.psm1 +468 -0
  244. package/resources/lib/discovery-validation/DiscoveryEncoding.psm1 +156 -0
  245. package/resources/lib/discovery-validation/DiscoveryManifest.psm1 +384 -0
  246. package/resources/lib/discovery-validation/DiscoveryObservation.psm1 +217 -0
  247. package/resources/lib/discovery-validation/DiscoveryPayload.psm1 +276 -0
  248. package/resources/lib/discovery-validation/DiscoveryPlanning.psm1 +336 -0
  249. package/resources/lib/discovery-validation/DiscoveryRootGrant.psm1 +164 -0
  250. package/resources/lib/discovery-validation/DiscoveryStart.psm1 +440 -0
  251. package/resources/lib/discovery-validation/DiscoveryStartRecord.psm1 +296 -0
  252. package/resources/lib/discovery-validation/DiscoveryStop.psm1 +336 -0
  253. package/resources/lib/discovery-validation/DiscoveryToolRouting.psm1 +228 -0
  254. package/resources/powershell/PoshQC/PoshQC.Parallel.psm1 +452 -0
  255. package/resources/powershell/PoshQC/PoshQC.Shard.psm1 +106 -8
  256. package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +12 -0
  257. package/resources/powershell/PoshQC/PoshQC.psd1 +6 -1
  258. package/resources/powershell/PoshQC/PoshQC.psm1 +7 -1
  259. package/resources/powershell/PoshQC/README.md +20 -1
  260. package/resources/templates/policy_audit/code-review.yyyy-MM-ddTHH-mm.md +4 -4
  261. package/resources/templates/policy_audit/policy-audit.yyyy-MM-ddTHH-mm.md +4 -4
@@ -0,0 +1,369 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Codex twin of the HookTargetWorktree target-worktree resolver functions (issue #1009).
4
+
5
+ .DESCRIPTION
6
+ Source: .claude/lib/worktree-resolution/HookTargetWorktree.psm1. This file carries the
7
+ six functions of that module with byte-identical function text, because Codex hooks
8
+ cannot import .claude/lib in a consumer repository: a consumer receives the .codex
9
+ runtime without the Claude library. tests/scripts/codex-hooks/hook-target-worktree.Tests.ps1
10
+ holds the function names and each function's text equal to the module and runs the
11
+ shared resolver behavior rows against this file.
12
+
13
+ Functions-only: the file has no entry point and no statement outside the function
14
+ definitions. It is dot-sourced by .codex/hooks/enforce-python-batch-budget.ps1 and
15
+ .codex/hooks/enforce-powershell-batch-budget.ps1. Edit the module first, then copy the
16
+ changed function text here.
17
+
18
+ .NOTES
19
+ Compatible with PowerShell 7+. Mirrored byte-identically under
20
+ extensions/drm-copilot/resources/codex-and-agents-customizations/.
21
+ #>
22
+
23
+ function ConvertTo-HookTargetWorktreeNormalizedPath {
24
+ <#
25
+ .SYNOPSIS
26
+ Normalize a path to forward slashes with repeated and trailing slashes removed.
27
+ .DESCRIPTION
28
+ Backslashes become forward slashes, runs of slashes collapse to one, and a trailing
29
+ slash is trimmed except from a bare root ('/' or a drive root such as 'C:/'). Blank
30
+ input returns an empty string. Case is preserved; callers compare with
31
+ OrdinalIgnoreCase.
32
+ .PARAMETER Path
33
+ The path to normalize.
34
+ #>
35
+ [CmdletBinding()]
36
+ [OutputType([string])]
37
+ param(
38
+ [AllowNull()] [AllowEmptyString()] [string] $Path
39
+ )
40
+
41
+ if ([string]::IsNullOrWhiteSpace($Path)) { return '' }
42
+ $normalized = ($Path.Trim() -replace '\\', '/') -replace '/{2,}', '/'
43
+ if ($normalized.Length -gt 1 -and $normalized.EndsWith('/') -and $normalized -notmatch '^[A-Za-z]:/$') {
44
+ $normalized = $normalized.Substring(0, $normalized.Length - 1)
45
+ }
46
+ return $normalized
47
+ }
48
+
49
+ function Get-HookTargetWorktreeRelativePath {
50
+ <#
51
+ .SYNOPSIS
52
+ Return a path relative to a worktree root, or $null when it lies outside the root.
53
+ .DESCRIPTION
54
+ Both values are normalized first. A path equal to the root returns an empty string;
55
+ a path under the root returns its forward-slash remainder; any other path, or a
56
+ blank value, returns $null.
57
+ .PARAMETER Path
58
+ The path to express relative to the root.
59
+ .PARAMETER WorktreeRoot
60
+ The worktree root.
61
+ #>
62
+ [CmdletBinding()]
63
+ [OutputType([string])]
64
+ param(
65
+ [AllowNull()] [AllowEmptyString()] [string] $Path,
66
+ [AllowNull()] [AllowEmptyString()] [string] $WorktreeRoot
67
+ )
68
+
69
+ $normalizedPath = ConvertTo-HookTargetWorktreeNormalizedPath -Path $Path
70
+ $normalizedRoot = ConvertTo-HookTargetWorktreeNormalizedPath -Path $WorktreeRoot
71
+ if ([string]::IsNullOrEmpty($normalizedPath) -or [string]::IsNullOrEmpty($normalizedRoot)) { return $null }
72
+ if ([string]::Equals($normalizedPath, $normalizedRoot, [System.StringComparison]::OrdinalIgnoreCase)) { return '' }
73
+ $prefix = if ($normalizedRoot.EndsWith('/')) { $normalizedRoot } else { $normalizedRoot + '/' }
74
+ if ($normalizedPath.StartsWith($prefix, [System.StringComparison]::OrdinalIgnoreCase)) {
75
+ return $normalizedPath.Substring($prefix.Length)
76
+ }
77
+ return $null
78
+ }
79
+
80
+ function Get-HookTargetWorktreeEnclosingRoot {
81
+ <#
82
+ .SYNOPSIS
83
+ Return the nearest root that encloses a path, or $null when none does.
84
+ .DESCRIPTION
85
+ A root encloses a path when the normalized path equals the normalized root or
86
+ starts with the root followed by a slash. When several roots enclose the path, the
87
+ longest one wins, so a worktree nested inside another wins for paths under it.
88
+ .PARAMETER Path
89
+ The path to place.
90
+ .PARAMETER Roots
91
+ The candidate worktree roots.
92
+ #>
93
+ [CmdletBinding()]
94
+ [OutputType([string])]
95
+ param(
96
+ [AllowNull()] [AllowEmptyString()] [string] $Path,
97
+ [AllowNull()] [AllowEmptyCollection()] [string[]] $Roots
98
+ )
99
+
100
+ $best = $null
101
+ foreach ($root in @($Roots)) {
102
+ $normalizedRoot = ConvertTo-HookTargetWorktreeNormalizedPath -Path $root
103
+ if ([string]::IsNullOrEmpty($normalizedRoot)) { continue }
104
+ $relative = Get-HookTargetWorktreeRelativePath -Path $Path -WorktreeRoot $normalizedRoot
105
+ if ($null -ne $relative -and ($null -eq $best -or $normalizedRoot.Length -gt $best.Length)) { $best = $normalizedRoot }
106
+ }
107
+ return $best
108
+ }
109
+
110
+ function Get-HookTargetWorktreeKey {
111
+ <#
112
+ .SYNOPSIS
113
+ Return the stable key '<sanitized leaf>-<8 hex>' that names a worktree root.
114
+ .DESCRIPTION
115
+ The hex part is the first four bytes of the SHA-256 of the normalized root with no
116
+ trailing slash, and the leaf is reduced to file-name-safe characters. The algorithm
117
+ equals the worktree-derived batch-budget session id, which prefixes 'worktree-'.
118
+ .PARAMETER WorktreeRoot
119
+ The worktree root to key.
120
+ #>
121
+ [CmdletBinding()]
122
+ [OutputType([string])]
123
+ param(
124
+ [Parameter(Mandatory)] [string] $WorktreeRoot
125
+ )
126
+
127
+ $normalizedRoot = (ConvertTo-HookTargetWorktreeNormalizedPath -Path $WorktreeRoot).TrimEnd('/')
128
+ $leaf = $normalizedRoot.Substring($normalizedRoot.LastIndexOf('/') + 1) -replace '[^A-Za-z0-9._-]', '_'
129
+ $hashBytes = [System.Security.Cryptography.SHA256]::HashData([System.Text.Encoding]::UTF8.GetBytes($normalizedRoot))
130
+ $shortHash = -join (@($hashBytes[0..3]) | ForEach-Object { $_.ToString('x2') })
131
+ return "$leaf-$shortHash"
132
+ }
133
+
134
+ function ConvertFrom-HookTargetWorktreePorcelain {
135
+ <#
136
+ .SYNOPSIS
137
+ Parse `git worktree list --porcelain` text into worktree records.
138
+ .DESCRIPTION
139
+ Emits one record per non-bare stanza with Root (normalized), Branch (the short
140
+ branch name, or $null when detached), Bare, and Prunable. A bare stanza is skipped.
141
+ Blank lines separate stanzas, and CRLF line endings are tolerated.
142
+ .PARAMETER Text
143
+ The porcelain text.
144
+ #>
145
+ [CmdletBinding()]
146
+ [OutputType([pscustomobject])]
147
+ param(
148
+ [AllowNull()] [AllowEmptyString()] [string] $Text
149
+ )
150
+
151
+ $records = [System.Collections.Generic.List[object]]::new()
152
+ $stanza = $null
153
+ foreach ($rawLine in @(([string] $Text -split "`r?`n") + '')) {
154
+ $line = $rawLine.Trim()
155
+ if ($line -eq '' -or $line.StartsWith('worktree ')) {
156
+ if ($null -ne $stanza -and -not $stanza.Bare) {
157
+ $records.Add([pscustomobject]@{ Root = $stanza.Root; Branch = $stanza.Branch; Bare = $false; Prunable = $stanza.Prunable })
158
+ }
159
+ $stanza = $null
160
+ if ($line -ne '') {
161
+ $stanza = @{ Root = (ConvertTo-HookTargetWorktreeNormalizedPath -Path $line.Substring(9)); Branch = $null; Bare = $false; Prunable = $false }
162
+ }
163
+ continue
164
+ }
165
+ if ($null -eq $stanza) { continue }
166
+ if ($line -eq 'bare') {
167
+ $stanza.Bare = $true
168
+ } elseif ($line.StartsWith('branch ')) {
169
+ $reference = $line.Substring(7).Trim()
170
+ $stanza.Branch = if ($reference.StartsWith('refs/heads/')) { $reference.Substring(11) } else { $reference }
171
+ } elseif ($line -eq 'detached') {
172
+ $stanza.Branch = $null
173
+ } elseif ($line -eq 'prunable' -or $line.StartsWith('prunable ')) {
174
+ $stanza.Prunable = $true
175
+ }
176
+ }
177
+ return $records.ToArray()
178
+ }
179
+
180
+ function Resolve-HookTargetWorktree {
181
+ <#
182
+ .SYNOPSIS
183
+ Resolve the registered worktree that a hook call acts on.
184
+ .DESCRIPTION
185
+ The first present source decides, in the order FilePath, CommandOperand (paths
186
+ and/or branch), DelegationIdentity, SessionRoot; a later source is never consulted.
187
+ Relative paths map to the session root without enumerating worktrees. An absolute
188
+ path maps to its nearest enclosing registered worktree, and a path inside none, or
189
+ an invoker that throws or returns no worktree, falls back to the session root.
190
+ Disagreeing components yield TARGET_WORKTREE_AMBIGUOUS; a present branch or
191
+ identity that names no worktree yields TARGET_WORKTREE_NOT_DERIVABLE and never the
192
+ session root. The result carries WorktreeRoot, Source, Ambiguous, ReasonCode,
193
+ Detail, and Candidates. The invoker runs at most once.
194
+ .PARAMETER SessionRoot
195
+ The absolute session root (the hook's root); the fallback root.
196
+ .PARAMETER FilePath
197
+ File-tool target paths.
198
+ .PARAMETER CommandOperandPath
199
+ Command operand paths parsed by the caller.
200
+ .PARAMETER CommandBranch
201
+ A command branch operand parsed by the caller.
202
+ .PARAMETER DelegationPrompt
203
+ Agent delegation prompt text; its 'branch:' label and canonical issue line are read.
204
+ .PARAMETER CheckpointIssueReader
205
+ Optional { param($WorktreeRoot) <issue number or $null> } used only for an issue identity.
206
+ .PARAMETER WorktreeListInvoker
207
+ { param($SessionRoot) <porcelain text> }; the default runs git worktree list --porcelain.
208
+ #>
209
+ [CmdletBinding()]
210
+ [OutputType([pscustomobject])]
211
+ param(
212
+ [Parameter(Mandatory)] [string] $SessionRoot,
213
+ [AllowNull()] [AllowEmptyCollection()] [string[]] $FilePath,
214
+ [AllowNull()] [AllowEmptyCollection()] [string[]] $CommandOperandPath,
215
+ [AllowNull()] [AllowEmptyString()] [string] $CommandBranch,
216
+ [AllowNull()] [AllowEmptyString()] [string] $DelegationPrompt,
217
+ [scriptblock] $CheckpointIssueReader,
218
+ [scriptblock] $WorktreeListInvoker = { param($SessionRoot) $porcelain = & git -C $SessionRoot worktree list --porcelain 2>$null; if ($LASTEXITCODE -ne 0) { return '' }; return ($porcelain -join "`n") }
219
+ )
220
+
221
+ $ambiguousCode = 'TARGET_WORKTREE_AMBIGUOUS'
222
+ $notDerivableCode = 'TARGET_WORKTREE_NOT_DERIVABLE'
223
+ $ignoreCase = [System.StringComparison]::OrdinalIgnoreCase
224
+ $absolutePattern = '^(/|[A-Za-z]:/)'
225
+ $session = ConvertTo-HookTargetWorktreeNormalizedPath -Path $SessionRoot
226
+
227
+ # Nested helpers are called by constant name and read this function's variables.
228
+ function Get-HookTargetResult {
229
+ param($Root, [string] $Source, $Code, [string] $Detail = '', [string[]] $Candidates = @())
230
+ [pscustomobject]@{
231
+ WorktreeRoot = $Root
232
+ Source = $Source
233
+ Ambiguous = ($Code -eq $ambiguousCode)
234
+ ReasonCode = $Code
235
+ Detail = $Detail
236
+ Candidates = [string[]] @($Candidates)
237
+ }
238
+ }
239
+ function Add-HookTargetDistinctValue {
240
+ param([System.Collections.Generic.List[string]] $List, [string] $Value)
241
+ foreach ($existing in $List) { if ([string]::Equals($existing, $Value, $ignoreCase)) { return } }
242
+ $List.Add($Value)
243
+ }
244
+ function Get-HookTargetRecordedIssue {
245
+ param([string] $Root)
246
+ try { $value = ([string] (& $CheckpointIssueReader $Root)).Trim().TrimStart('#') } catch { return $null }
247
+ if ($value -notmatch '^\d+$') { return $null }
248
+ $digits = $value.TrimStart('0')
249
+ return $(if ($digits -eq '') { '0' } else { $digits })
250
+ }
251
+ function Resolve-HookTargetPathSource {
252
+ param([string[]] $Paths, [string] $Source)
253
+ $resolved = [System.Collections.Generic.List[string]]::new()
254
+ $details = [System.Collections.Generic.List[string]]::new()
255
+ $fellBack = $false
256
+ foreach ($candidate in $Paths) {
257
+ $normalized = ConvertTo-HookTargetWorktreeNormalizedPath -Path $candidate
258
+ $root = $session
259
+ if ($normalized -notmatch $absolutePattern) {
260
+ $fellBack = $true
261
+ $details.Add("relative path '$normalized' maps to the session root")
262
+ } else {
263
+ $enclosing = Get-HookTargetWorktreeEnclosingRoot -Path $normalized -Roots $roots
264
+ if ($null -eq $enclosing) {
265
+ $fellBack = $true
266
+ $details.Add($(if ($listDetail) { $listDetail } else { "path '$normalized' is inside no registered worktree" }))
267
+ } else {
268
+ $root = $enclosing
269
+ }
270
+ }
271
+ Add-HookTargetDistinctValue -List $resolved -Value $root
272
+ }
273
+ if ($resolved.Count -gt 1) {
274
+ return (Get-HookTargetResult -Root $null -Source $Source -Code $ambiguousCode -Detail ('the paths resolve to {0} different worktrees' -f $resolved.Count) -Candidates $resolved.ToArray())
275
+ }
276
+ $decidedBy = if ($fellBack) { 'SessionRoot' } else { $Source }
277
+ return (Get-HookTargetResult -Root $resolved[0] -Source $decidedBy -Code $null -Detail ($details -join '; '))
278
+ }
279
+ function Resolve-HookTargetBranchSource {
280
+ param([string] $Branch, [string] $Source)
281
+ $matched = @($records | Where-Object { $null -ne $_.Branch -and [string]::Equals($_.Branch, $Branch, $ignoreCase) } | ForEach-Object { $_.Root })
282
+ if ($matched.Count -eq 0) { return (Get-HookTargetResult -Root $null -Source $Source -Code $notDerivableCode -Detail "branch '$Branch' is checked out in no registered worktree") }
283
+ if ($matched.Count -gt 1) { return (Get-HookTargetResult -Root $null -Source $Source -Code $ambiguousCode -Detail "branch '$Branch' is checked out in $($matched.Count) registered worktrees" -Candidates $matched) }
284
+ return (Get-HookTargetResult -Root $matched[0] -Source $Source -Code $null)
285
+ }
286
+
287
+ # Select the deciding source: the first present one in precedence order.
288
+ $filePaths = @($FilePath | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
289
+ $operandPaths = @($CommandOperandPath | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
290
+ $branchOperand = if ([string]::IsNullOrWhiteSpace($CommandBranch)) { '' } else { $CommandBranch.Trim() }
291
+ $branches = [System.Collections.Generic.List[string]]::new()
292
+ $issues = [System.Collections.Generic.List[string]]::new()
293
+ if ($filePaths.Count -gt 0) {
294
+ $source = 'FilePath'
295
+ } elseif ($operandPaths.Count -gt 0 -or $branchOperand) {
296
+ $source = 'CommandOperand'
297
+ } elseif (-not [string]::IsNullOrWhiteSpace($DelegationPrompt)) {
298
+ $source = 'DelegationIdentity'
299
+ foreach ($match in [regex]::Matches($DelegationPrompt, '(?i)\bbranch:\s*(?<name>[A-Za-z0-9][A-Za-z0-9._/-]*)')) {
300
+ Add-HookTargetDistinctValue -List $branches -Value $match.Groups['name'].Value.TrimEnd('.', '/')
301
+ }
302
+ foreach ($match in [regex]::Matches($DelegationPrompt, 'Canonical issue number for this feature is #?(?<number>\d+)')) {
303
+ $digits = $match.Groups['number'].Value.TrimStart('0')
304
+ Add-HookTargetDistinctValue -List $issues -Value $(if ($digits -eq '') { '0' } else { $digits })
305
+ }
306
+ } else {
307
+ return (Get-HookTargetResult -Root $session -Source 'SessionRoot' -Code $null -Detail 'no target source is present; the session root applies')
308
+ }
309
+
310
+ # Enumerate registered worktrees at most once, and only when the deciding source needs them.
311
+ $needsList = switch ($source) {
312
+ 'FilePath' { @($filePaths | Where-Object { (ConvertTo-HookTargetWorktreeNormalizedPath -Path $_) -match $absolutePattern }).Count -gt 0 }
313
+ 'CommandOperand' { [bool] $branchOperand -or @($operandPaths | Where-Object { (ConvertTo-HookTargetWorktreeNormalizedPath -Path $_) -match $absolutePattern }).Count -gt 0 }
314
+ default { ($branches.Count -eq 1 -and $issues.Count -le 1) -or ($branches.Count -eq 0 -and $issues.Count -eq 1 -and $null -ne $CheckpointIssueReader) }
315
+ }
316
+ $records = @()
317
+ $listDetail = ''
318
+ if ($needsList) {
319
+ try {
320
+ $records = @(ConvertFrom-HookTargetWorktreePorcelain -Text (@(& $WorktreeListInvoker $SessionRoot) -join "`n"))
321
+ if ($records.Count -eq 0) { $listDetail = 'the worktree list returned no registered worktree' }
322
+ } catch {
323
+ $records = @()
324
+ $listDetail = "the worktree list failed: $($_.Exception.Message)"
325
+ }
326
+ }
327
+ $roots = @($records | ForEach-Object { $_.Root })
328
+
329
+ if ($source -eq 'FilePath') { return (Resolve-HookTargetPathSource -Paths $filePaths -Source 'FilePath') }
330
+
331
+ if ($source -eq 'CommandOperand') {
332
+ $pathResult = if ($operandPaths.Count -gt 0) { Resolve-HookTargetPathSource -Paths $operandPaths -Source 'CommandOperand' } else { $null }
333
+ if (-not $branchOperand) { return $pathResult }
334
+ $branchResult = Resolve-HookTargetBranchSource -Branch $branchOperand -Source 'CommandOperand'
335
+ if ($null -eq $pathResult) { return $branchResult }
336
+ if ($pathResult.Ambiguous) { return $pathResult }
337
+ if ($null -ne $branchResult.ReasonCode) { return $branchResult }
338
+ if (-not [string]::Equals($pathResult.WorktreeRoot, $branchResult.WorktreeRoot, $ignoreCase)) {
339
+ return (Get-HookTargetResult -Root $null -Source 'CommandOperand' -Code $ambiguousCode -Detail "the operand paths and branch '$branchOperand' resolve to different worktrees" -Candidates @($pathResult.WorktreeRoot, $branchResult.WorktreeRoot))
340
+ }
341
+ return $branchResult
342
+ }
343
+
344
+ if ($branches.Count -gt 1) { return (Get-HookTargetResult -Root $null -Source $source -Code $ambiguousCode -Detail ('the prompt names {0} different branches: {1}' -f $branches.Count, ($branches -join ', '))) }
345
+ if ($issues.Count -gt 1) { return (Get-HookTargetResult -Root $null -Source $source -Code $ambiguousCode -Detail ('the prompt names {0} different issue numbers: {1}' -f $issues.Count, ($issues -join ', '))) }
346
+ if ($branches.Count -eq 1) {
347
+ $branchResult = Resolve-HookTargetBranchSource -Branch $branches[0] -Source $source
348
+ if ($null -ne $branchResult.ReasonCode -or $issues.Count -eq 0 -or $null -eq $CheckpointIssueReader) { return $branchResult }
349
+ $target = $branchResult.WorktreeRoot
350
+ $recorded = Get-HookTargetRecordedIssue -Root $target
351
+ if ($null -ne $recorded) {
352
+ if ($recorded -eq $issues[0]) { return $branchResult }
353
+ return (Get-HookTargetResult -Root $null -Source $source -Code $ambiguousCode -Detail "branch '$($branches[0])' places the call in a worktree whose checkpoint records issue $recorded, not issue $($issues[0])" -Candidates @($target))
354
+ }
355
+ $elsewhere = @($records | Where-Object { -not [string]::Equals($_.Root, $target, $ignoreCase) -and (Get-HookTargetRecordedIssue -Root $_.Root) -eq $issues[0] } | ForEach-Object { $_.Root })
356
+ if ($elsewhere.Count -gt 0) {
357
+ return (Get-HookTargetResult -Root $null -Source $source -Code $ambiguousCode -Detail "branch '$($branches[0])' and issue $($issues[0]) place the call in different worktrees" -Candidates (@($target) + $elsewhere))
358
+ }
359
+ return $branchResult
360
+ }
361
+ if ($issues.Count -eq 1) {
362
+ if ($null -eq $CheckpointIssueReader) { return (Get-HookTargetResult -Root $null -Source $source -Code $notDerivableCode -Detail "issue $($issues[0]) cannot be placed without a checkpoint issue reader") }
363
+ $matched = @($records | Where-Object { (Get-HookTargetRecordedIssue -Root $_.Root) -eq $issues[0] } | ForEach-Object { $_.Root })
364
+ if ($matched.Count -eq 0) { return (Get-HookTargetResult -Root $null -Source $source -Code $notDerivableCode -Detail "issue $($issues[0]) is recorded by no registered worktree") }
365
+ if ($matched.Count -gt 1) { return (Get-HookTargetResult -Root $null -Source $source -Code $ambiguousCode -Detail "issue $($issues[0]) is recorded by $($matched.Count) registered worktrees" -Candidates $matched) }
366
+ return (Get-HookTargetResult -Root $matched[0] -Source $source -Code $null)
367
+ }
368
+ return (Get-HookTargetResult -Root $null -Source $source -Code $notDerivableCode -Detail 'the prompt carries no branch: label and no canonical issue line')
369
+ }
@@ -13,6 +13,7 @@ param()
13
13
  . (Join-Path $PSScriptRoot 'codex-authority-store.ps1')
14
14
  . (Join-Path $PSScriptRoot 'codex-agent-profile-attestation.ps1')
15
15
  . (Join-Path $PSScriptRoot 'codex-epic-child-launch-attestation.ps1')
16
+ . (Join-Path $PSScriptRoot 'discovery-start-attestation.ps1')
16
17
  $script:EpicPersonas = @('epic-planner', 'epic-orchestrator')
17
18
 
18
19
  function ConvertFrom-SubagentAttestationJson {
@@ -365,6 +366,13 @@ function Invoke-CodexSubagentAttestationCommand {
365
366
  )
366
367
  try {
367
368
  $payload = ConvertFrom-SubagentAttestationJson -Raw (& $ReadInput) -Name 'SubagentStart input'
369
+ if (Test-CodexDiscoveryAgentType -AgentType ([string]$payload.agent_type)) {
370
+ # A discovery specialist is attested against its protected invocation only;
371
+ # no checkpoint, HEAD or epic receipt is consulted (issue #980).
372
+ $attestation = Get-CodexDiscoveryStartAttestation -Payload $payload -RepositoryRoot $repositoryRoot -Now (& $GetNow)
373
+ $attestationPath = Write-CodexSubagentAttestation -RepositoryRoot $repositoryRoot -Attestation $attestation
374
+ return [ordered]@{ exit_code = 0; stdout = (Get-CodexDiscoveryStartCommandOutput -Attestation $attestation -AttestationPath $attestationPath); stderr = $null }
375
+ }
368
376
  $stateRoot = Join-Path $repositoryRoot 'artifacts/orchestration'
369
377
  $receiptPath = Get-CodexAuthorityReceiptPath `
370
378
  -RepositoryRoot $repositoryRoot `
@@ -31,7 +31,7 @@ function Test-CodexStopGatedAgent {
31
31
  [OutputType([bool])]
32
32
  param([Parameter(Mandatory)][string] $AgentType)
33
33
 
34
- if ($AgentType -match '-c(?:1|2|3|4|3-elevated)$') {
34
+ if ($AgentType -match '-c(?:1|2|3|4|3-elevated)$' -or (Test-CodexStopDiscoveryAgent -AgentType $AgentType)) {
35
35
  return $true
36
36
  }
37
37
  return @(
@@ -42,6 +42,19 @@ function Test-CodexStopGatedAgent {
42
42
  ) -contains $AgentType
43
43
  }
44
44
 
45
+ function Test-CodexStopDiscoveryAgent {
46
+ <#
47
+ .SYNOPSIS
48
+ True for a discovery specialist, whose stop requires the discovery-invocation start attestation (issue #980).
49
+ #>
50
+ [CmdletBinding()]
51
+ [OutputType([bool])]
52
+ param([AllowNull()][AllowEmptyString()][string] $AgentType)
53
+
54
+ return -not [string]::IsNullOrWhiteSpace($AgentType) -and
55
+ $AgentType -cmatch '^(legacy-parity-analyst|runtime-characterization-analyst|requirements-reconciler|migration-coverage-reviewer)(-c(1|2|3|4|3-elevated))?$'
56
+ }
57
+
45
58
  function Get-CodexStopContinuation {
46
59
  [CmdletBinding()]
47
60
  [OutputType([System.Collections.Specialized.OrderedDictionary])]
@@ -98,6 +111,14 @@ function Invoke-CodexSubagentStopDecision {
98
111
  return Get-CodexStopContinuation -Reason "EPIC_INVOCATION_ORIGIN_BLOCKED: '$agentType' lacks valid root provenance." -AlreadyContinued $alreadyContinued
99
112
  }
100
113
  }
114
+ if (Test-CodexStopDiscoveryAgent -AgentType $agentType) {
115
+ # A specialist's attestation must be the protected discovery-invocation receipt kind;
116
+ # the output authority itself is validated by validate-discovery-agent-output.ps1.
117
+ $attestationNames = @($attestation.PSObject.Properties.Name)
118
+ if ($attestationNames -notcontains 'receipt_kind' -or [string]$attestation.receipt_kind -cne 'discovery-invocation') {
119
+ return Get-CodexStopContinuation -Reason "DISCOVERY_START_ATTESTATION_BLOCKED: '$agentType' was not attested against a protected discovery invocation." -AlreadyContinued $alreadyContinued
120
+ }
121
+ }
101
122
  if ($attestation.routing_valid -isnot [bool] -or -not [bool]$attestation.routing_valid) {
102
123
  return Get-CodexStopContinuation -Reason "MODEL_ROUTING_ATTESTATION_BLOCKED: '$agentType' did not run under its recorded deployment model." -AlreadyContinued $alreadyContinued
103
124
  }
@@ -0,0 +1,178 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Native SubagentStop output validation adapter for Codex discovery agents.
4
+
5
+ .DESCRIPTION
6
+ Invoked by the Codex SubagentStop hook. The hook reads the Codex stop envelope
7
+ from stdin, derives the stopping principal from the payload alone (session, the
8
+ host-assigned agent_id and agent_type, and the literal parent root), and
9
+ takes its decision from the shared DiscoveryStop module (published under
10
+ .codex/lib/discovery-validation, or read from .claude/lib when this repository
11
+ hosts itself):
12
+
13
+ - a stop whose agent type is not a discovery specialist writes nothing, so the
14
+ routing validator and the other Codex stop gates keep their behavior;
15
+ - a discovery specialist may stop only when its protected invocation was
16
+ finalized through the gateway with a current, gateway-written completion
17
+ receipt whose required outputs are present and whose inputs are unchanged;
18
+ - a stop that cannot be validated requests one continuation (decision=block at
19
+ exit 0) and, when stop_hook_active is already true, ends the stop with the
20
+ reason instead of looping.
21
+
22
+ An envelope the hook cannot read writes the reason to stderr at exit 2.
23
+ Dependency failures block with the DISCOVERY_ARTIFACT_GATE_BLOCKED: prefix
24
+ (issue #980). No orchestrator checkpoint is read or written.
25
+
26
+ .NOTES
27
+ Requires PowerShell 7+. Invokes NO external process.
28
+ #>
29
+ [CmdletBinding()]
30
+ param()
31
+ $script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
32
+
33
+ function Get-DiscoveryStopHelperModulePath {
34
+ <#
35
+ .SYNOPSIS
36
+ Returns the published (.codex/lib) or self-hosting (.claude/lib) path of one helper module.
37
+ #>
38
+ [CmdletBinding()]
39
+ [OutputType([string])]
40
+ param(
41
+ [Parameter(Mandatory = $true)][string]$ModuleName,
42
+ [Parameter(Mandatory = $false)][string]$ScriptRoot = $PSScriptRoot
43
+ )
44
+
45
+ $published = Join-Path $ScriptRoot "../lib/discovery-validation/$ModuleName"
46
+ $selfHosted = Join-Path $ScriptRoot "../../.claude/lib/discovery-validation/$ModuleName"
47
+ foreach ($candidate in @($published, $selfHosted)) {
48
+ if (Test-Path -LiteralPath $candidate -PathType Leaf) { return $candidate }
49
+ }
50
+ return $published
51
+ }
52
+
53
+ function Import-DiscoveryOutputSelfHostedModule {
54
+ <#
55
+ .SYNOPSIS
56
+ Imports the shared helpers from this repository's .claude/lib layout when no published .codex/lib exists (exemption D4).
57
+ #>
58
+ [CmdletBinding()]
59
+ param()
60
+
61
+ $ScriptRoot = $PSScriptRoot
62
+ try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryEncoding.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryEncoding.psm1' -ErrorRecord $_ }
63
+ try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryAuthority.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryAuthority.psm1' -ErrorRecord $_ }
64
+ try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryManifest.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryManifest.psm1' -ErrorRecord $_ }
65
+ try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryPayload.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryPayload.psm1' -ErrorRecord $_ }
66
+ try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryStartRecord.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStartRecord.psm1' -ErrorRecord $_ }
67
+ try { Import-Module (Join-Path $ScriptRoot '../../.claude/lib/discovery-validation/DiscoveryStop.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStop.psm1' -ErrorRecord $_ }
68
+ }
69
+
70
+ # The published destination keeps the helpers beside .codex/hooks; this repository hosts them under .claude/lib.
71
+ if (Test-Path -LiteralPath (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryEncoding.psm1') -PathType Leaf) {
72
+ try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryEncoding.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryEncoding.psm1' -ErrorRecord $_ }
73
+ try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryAuthority.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryAuthority.psm1' -ErrorRecord $_ }
74
+ try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryManifest.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryManifest.psm1' -ErrorRecord $_ }
75
+ try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryPayload.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryPayload.psm1' -ErrorRecord $_ }
76
+ try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryStartRecord.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStartRecord.psm1' -ErrorRecord $_ }
77
+ try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryStop.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStop.psm1' -ErrorRecord $_ }
78
+ } else {
79
+ Import-DiscoveryOutputSelfHostedModule
80
+ }
81
+
82
+ $script:DiscoveryGateReasonPrefix = 'DISCOVERY_ARTIFACT_GATE_BLOCKED:'
83
+
84
+ function Invoke-DiscoveryAgentOutputDecision {
85
+ <#
86
+ .SYNOPSIS
87
+ Parses the Codex SubagentStop envelope and returns the shared stop outcome.
88
+ .DESCRIPTION
89
+ Returns the outcome object (Decision skip, allow or block; Code; Reason;
90
+ Receipt; Invocation). Every seam defaults to the real host and is injectable.
91
+ A recorded dependency failure blocks before the envelope is read.
92
+ #>
93
+ [CmdletBinding()]
94
+ [OutputType([pscustomobject])]
95
+ param(
96
+ [Parameter(Mandatory = $false)][AllowNull()][AllowEmptyString()][string]$PayloadRaw,
97
+ [Parameter(Mandatory = $false)][AllowNull()][hashtable]$HostEnvironment = $null,
98
+ [Parameter(Mandatory = $false)][AllowNull()][hashtable]$Store = $null,
99
+ [Parameter(Mandatory = $false)][AllowNull()][scriptblock]$ReadBytes = $null
100
+ )
101
+ $dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix $script:DiscoveryGateReasonPrefix
102
+ if ($null -ne $dependencyDecision) { return $dependencyDecision }
103
+
104
+ if ($null -eq $HostEnvironment) { $HostEnvironment = Get-DiscoveryTrustedHostEnvironment }
105
+ if ($null -eq $Store) { $Store = Get-DiscoveryStartStore }
106
+
107
+ $normalized = ConvertFrom-DiscoveryHostPayloadText -HostName 'codex' -Text $PayloadRaw
108
+ $assistantText = ''
109
+ $stopHookActive = $false
110
+ if ($null -eq $normalized.Anomaly) {
111
+ $payload = ConvertFrom-Json -InputObject $PayloadRaw -Depth 16
112
+ $names = @($payload.PSObject.Properties.Name)
113
+ if ($names -contains 'last_assistant_message' -and $payload.last_assistant_message -is [string]) { $assistantText = [string]$payload.last_assistant_message }
114
+ if ($names -contains 'stop_hook_active' -and $payload.stop_hook_active -is [bool]) { $stopHookActive = [bool]$payload.stop_hook_active }
115
+ }
116
+ $parameters = @{
117
+ Normalized = $normalized; HostEnvironment = $HostEnvironment
118
+ AssistantText = $assistantText; StopHookActive = $stopHookActive; Store = $Store
119
+ }
120
+ if ($null -ne $ReadBytes) { $parameters['ReadBytes'] = $ReadBytes }
121
+ return Get-DiscoveryStopDecision @parameters
122
+ }
123
+
124
+ function Get-DiscoveryAgentOutputContinuation {
125
+ <#
126
+ .SYNOPSIS
127
+ Renders a blocked stop as the Codex continuation (decision=block) or, when already continued, the stop reason.
128
+ #>
129
+ [CmdletBinding()]
130
+ [OutputType([System.Collections.Specialized.OrderedDictionary])]
131
+ param(
132
+ [Parameter(Mandatory = $true)][string]$Reason,
133
+ [Parameter(Mandatory = $true)][bool]$AlreadyContinued
134
+ )
135
+
136
+ if ($AlreadyContinued) {
137
+ return [ordered]@{ continue = $false; stopReason = $Reason; systemMessage = $Reason }
138
+ }
139
+ return [ordered]@{ decision = 'block'; reason = $Reason }
140
+ }
141
+
142
+ function Invoke-DiscoveryAgentOutputEntryPoint {
143
+ <#
144
+ .SYNOPSIS
145
+ Reads one Codex SubagentStop payload, writes the decision and returns the process exit code.
146
+ .DESCRIPTION
147
+ An unreadable envelope or a dependency failure writes its reason to stderr and
148
+ returns 2. A blocked stop writes the continuation JSON and returns 0; a
149
+ CONTINUED allow writes the stop reason JSON and returns 0. A skipped or
150
+ validated stop writes nothing and returns 0.
151
+ #>
152
+ [CmdletBinding()]
153
+ [OutputType([int])]
154
+ param([Parameter(Mandatory = $false)][AllowNull()][AllowEmptyString()][string]$PayloadRaw)
155
+
156
+ $outcome = Invoke-DiscoveryAgentOutputDecision -PayloadRaw $PayloadRaw
157
+ # A dependency failure is already the SubagentStop block result (ExitCode, Reason).
158
+ if ($null -ne $outcome.PSObject.Properties['ExitCode']) { [Console]::Error.WriteLine([string]$outcome.Reason); return [int]$outcome.ExitCode }
159
+ if ($outcome.Code -eq 'ENVELOPE') {
160
+ [Console]::Error.WriteLine("$($script:DiscoveryGateReasonPrefix) $($outcome.Reason)")
161
+ return 2
162
+ }
163
+ if ($outcome.Decision -eq 'block' -or $outcome.Code -eq 'CONTINUED') {
164
+ $continuation = Get-DiscoveryAgentOutputContinuation -Reason "$($script:DiscoveryGateReasonPrefix) $($outcome.Reason)" -AlreadyContinued ($outcome.Code -eq 'CONTINUED')
165
+ [Console]::Out.WriteLine(($continuation | ConvertTo-Json -Compress -Depth 5))
166
+ }
167
+ return 0
168
+ }
169
+
170
+ # Guard allows dot-sourcing in tests without executing the entrypoint.
171
+ if ($MyInvocation.InvocationName -eq '.') {
172
+ return
173
+ }
174
+ if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('DISCOVERY_ARTIFACT_GATE_BLOCKED: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
175
+ $dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'DISCOVERY_ARTIFACT_GATE_BLOCKED:'
176
+ if ($null -ne $dependencyDecision) { [Console]::Error.WriteLine($dependencyDecision.Reason); exit $dependencyDecision.ExitCode }
177
+
178
+ exit (Invoke-DiscoveryAgentOutputEntryPoint -PayloadRaw ([Console]::In.ReadToEnd()))
@@ -49,6 +49,14 @@ function Invoke-CodexTopologyCli {
49
49
  Default = $null
50
50
  }
51
51
  '--cross-cutting' = @{ Key = 'cross_cutting'; Kind = 'switch'; Required = $false; Default = $false }
52
+ '--invocation-kind' = @{
53
+ Key = 'invocation_kind'
54
+ Kind = 'value'
55
+ Required = $false
56
+ Choices = @('ordinary', 'discovery')
57
+ Default = 'ordinary'
58
+ }
59
+ '--skill-id' = @{ Key = 'skill_id'; Kind = 'value'; Required = $false; Default = $null }
52
60
  '--root-persona' = @{
53
61
  Key = 'root_persona'
54
62
  Kind = 'value'
@@ -79,7 +87,9 @@ function Invoke-CodexTopologyCli {
79
87
  -TestFileCount $values['test_file_count'] `
80
88
  -ExecutionContext $values['execution_context'] `
81
89
  -CrossCutting ([bool]$values['cross_cutting']) `
82
- -RootPersona $values['root_persona']
90
+ -RootPersona $values['root_persona'] `
91
+ -InvocationKind $values['invocation_kind'] `
92
+ -SkillId $values['skill_id']
83
93
  } catch [System.ArgumentException] {
84
94
  return New-CodexRoutingCliResult -ExitCode 1 -Stderr "$($_.Exception.Message)`n"
85
95
  }
@@ -83,7 +83,7 @@ If the marker is missing or malformed, fail closed to `full-feature`.
83
83
  Stop implementation and return to the user when:
84
84
 
85
85
  - the scope estimate or an in-flight batch would exceed the 3-production-file cap in direct mode,
86
- - a file is near or would exceed the 500-line limit,
86
+ - a file is above or would exceed the 800-line hard limit of the tiered file-size policy (split it before proceeding; at 500 lines look for a logical split, and at 700 lines split more aggressively),
87
87
  - any QA gate delta is non-zero after self-correction,
88
88
  - the toolchain cannot be executed in the current environment (mark the change **unverified**),
89
89
  - orchestrator handoff mode is requested but the required context package is incomplete,